diff --git a/README.rst b/README.rst
index 719c92c..e0501ae 100644
--- a/README.rst
+++ b/README.rst
@@ -399,6 +399,28 @@ This removes the need for the extra variable in the global namespace and the coo
 Our patch for this has been incorporated upstream, so this is forwards-compatible too, following Peewee's next release.
 
 
+Passing an Empty List/Set/Tuple into IN Doesn't Gen Invalid SQL
+---------------------------------------------------------------
+
+If you try to do a IN operation on an empty list:
+
+.. code-block:: python
+
+  User.select().where(User.id << [])
+
+Peewee will generate the following SQL:
+
+.. code-block:: sql
+
+  SELECT "t1"."id", "t1"."username" FROM "user" AS t1 WHERE ("t1"."id" IN ())
+
+Which the database will reject as invalid, throwing an exception.  We instead generate a "false" statement:
+
+.. code-block:: sql
+
+  SELECT u1.id, u1.username FROM "user" AS u1 WHERE (0 = 1)
+
+So you don't have to manually test for empty lists every time you use a SQL IN.
 
 
 
diff --git a/peewee.py b/peewee.py
index d609c21..de9fb2e 100644
--- a/peewee.py
+++ b/peewee.py
@@ -1598,6 +1598,8 @@ class QueryCompiler(object):
         lhs, lparams = self.parse_node(node.lhs, alias_map, conv)
         rhs, rparams = self.parse_node(node.rhs, alias_map, conv)
         template = '%s %s %s' if node.flat else '(%s %s %s)'
+        if node.op == OP.IN and node.rhs.__class__ in (list,set,tuple) and len(node.rhs)==0:
+          return template % ('0', self.get_op(OP.EQ), '1'), lparams
         sql = template % (lhs, self.get_op(node.op), rhs)
         return sql, lparams + rparams
 

Using << with an empty list creates an invalid SQL query
from @Prillan in https://github.com/coleifer/peewee/issues/860:

```
psycopg2.ProgrammingError: syntax error at or near ")"
```

I think either of the following solutions are acceptable:

- Throw an error in peewee indicating that the list (iterator) is empty.
- Transform column << [] into False before compiling to SQL.

Not handling this before sending it to the database causes all queries after it to fail (at least on our flask server) with error:

```
peewee.InternalError: current transaction is aborted, commands ignored until end of transaction block
```

diff --git a/playhouse/tests/test_models.py b/playhouse/tests/test_models.py
index e23e99d..2d9a691 100644
--- a/playhouse/tests/test_models.py
+++ b/playhouse/tests/test_models.py
@@ -131,6 +131,11 @@ class TestQueryingModels(ModelTestCase):
         users = User.select(fn.Count(fn.Distinct(User.username))).scalar()
         self.assertEqual(users, 6)
 
+    def test_empty_in(self):
+        for empty_collection in [list(), set(), tuple()]:
+            users = User.select().where(User.username << empty_collection)
+            self.assertEqual(users.count(), 0)
+
     def test_update(self):
         User.create_users(5)
         uq = User.update(username='u-edited').where(User.username << ['u1', 'u2', 'u3'])

pip install -e .
parse_log_pytest
pytest
pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
packaging @ file:///croot/packaging_1734472117206/work
-e git+https://github.com/keredson/peewee.git@817a27e0968d38dc974d89c19431ec88f871f3d3#egg=peewee
pluggy @ file:///croot/pluggy_1733169602837/work
pytest @ file:///croot/pytest_1738938843180/work
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work

name: peewee
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
prefix: /opt/conda/envs/peewee

playhouse/tests/test_models.py::TestQueryingModels::test_empty_in
playhouse/tests/test_models.py::TestModelAPIs::test_create_or_get playhouse/tests/test_models.py::TestModelAPIs::test_first playhouse/tests/test_models.py::TestModelAPIs::test_fk_cache_invalidated playhouse/tests/test_models.py::TestModelAPIs::test_fk_caching playhouse/tests/test_models.py::TestModelAPIs::test_save_fk
playhouse/tests/test_models.py::TestQueryingModels::test_delete playhouse/tests/test_models.py::TestQueryingModels::test_insert playhouse/tests/test_models.py::TestQueryingModels::test_insert_from playhouse/tests/test_models.py::TestQueryingModels::test_insert_many playhouse/tests/test_models.py::TestQueryingModels::test_insert_many_fallback playhouse/tests/test_models.py::TestQueryingModels::test_limits_offsets playhouse/tests/test_models.py::TestQueryingModels::test_model_iter playhouse/tests/test_models.py::TestQueryingModels::test_raw playhouse/tests/test_models.py::TestQueryingModels::test_raw_fn playhouse/tests/test_models.py::TestQueryingModels::test_scalar playhouse/tests/test_models.py::TestQueryingModels::test_select playhouse/tests/test_models.py::TestQueryingModels::test_select_all playhouse/tests/test_models.py::TestQueryingModels::test_select_get playhouse/tests/test_models.py::TestQueryingModels::test_select_subquery playhouse/tests/test_models.py::TestQueryingModels::test_select_with_bind_to playhouse/tests/test_models.py::TestQueryingModels::test_update playhouse/tests/test_models.py::TestQueryingModels::test_update_subquery playhouse/tests/test_models.py::TestInsertEmptyModel::test_insert_empty playhouse/tests/test_models.py::TestInsertEmptyModel::test_no_pk playhouse/tests/test_models.py::TestModelAPIs::test_callable_related_name playhouse/tests/test_models.py::TestModelAPIs::test_category_select_related_alias playhouse/tests/test_models.py::TestModelAPIs::test_count_transaction playhouse/tests/test_models.py::TestModelAPIs::test_counting playhouse/tests/test_models.py::TestModelAPIs::test_creation playhouse/tests/test_models.py::TestModelAPIs::test_deleting playhouse/tests/test_models.py::TestModelAPIs::test_dirty_from_query playhouse/tests/test_models.py::TestModelAPIs::test_exists playhouse/tests/test_models.py::TestModelAPIs::test_fk_exceptions playhouse/tests/test_models.py::TestModelAPIs::test_fk_ints playhouse/tests/test_models.py::TestModelAPIs::test_fk_object_id playhouse/tests/test_models.py::TestModelAPIs::test_get_exception playhouse/tests/test_models.py::TestModelAPIs::test_get_or_create playhouse/tests/test_models.py::TestModelAPIs::test_get_or_create_extended playhouse/tests/test_models.py::TestModelAPIs::test_meta_get_field_index playhouse/tests/test_models.py::TestModelAPIs::test_meta_rel_for_model playhouse/tests/test_models.py::TestModelAPIs::test_meta_remove_field playhouse/tests/test_models.py::TestModelAPIs::test_modify_model_cause_it_dirty playhouse/tests/test_models.py::TestModelAPIs::test_on_conflict playhouse/tests/test_models.py::TestModelAPIs::test_on_conflict_many playhouse/tests/test_models.py::TestModelAPIs::test_ordering playhouse/tests/test_models.py::TestModelAPIs::test_peek playhouse/tests/test_models.py::TestModelAPIs::test_reading playhouse/tests/test_models.py::TestModelAPIs::test_related_id playhouse/tests/test_models.py::TestModelAPIs::test_related_name playhouse/tests/test_models.py::TestModelAPIs::test_related_name_collision playhouse/tests/test_models.py::TestModelAPIs::test_save_dirty_auto playhouse/tests/test_models.py::TestModelAPIs::test_save_only playhouse/tests/test_models.py::TestModelAPIs::test_save_only_dirty_fields playhouse/tests/test_models.py::TestModelAPIs::test_saving playhouse/tests/test_models.py::TestModelAPIs::test_saving_via_create_gh111 playhouse/tests/test_models.py::TestModelAPIs::test_unicode playhouse/tests/test_models.py::TestModelAPIs::test_unicode_issue202 playhouse/tests/test_models.py::TestModelAPIs::test_zero_id playhouse/tests/test_models.py::TestAggregatesWithModels::test_aggregate_datetime playhouse/tests/test_models.py::TestAggregatesWithModels::test_aggregate_int playhouse/tests/test_models.py::TestAggregatesWithModels::test_annotate_datetime playhouse/tests/test_models.py::TestAggregatesWithModels::test_annotate_int playhouse/tests/test_models.py::TestMultiTableFromClause::test_from_multi_table playhouse/tests/test_models.py::TestMultiTableFromClause::test_join_on_query playhouse/tests/test_models.py::TestMultiTableFromClause::test_subselect playhouse/tests/test_models.py::TestMultiTableFromClause::test_subselect_with_column playhouse/tests/test_models.py::TestMultiTableFromClause::test_subselect_with_join playhouse/tests/test_models.py::TestDeleteRecursive::test_recursive_delete playhouse/tests/test_models.py::TestDeleteRecursive::test_recursive_delete_child_queries playhouse/tests/test_models.py::TestDeleteRecursive::test_recursive_delete_parent_sql playhouse/tests/test_models.py::TestDeleteRecursive::test_recursive_non_pk_fk playhouse/tests/test_models.py::TestDeleteRecursive::test_recursive_update playhouse/tests/test_models.py::TestTruncate::test_truncate playhouse/tests/test_models.py::TestManyToMany::test_m2m playhouse/tests/test_models.py::TestManyToMany::test_many_to_many_prefetch playhouse/tests/test_models.py::TestCustomModelOptionsBase::test_custom_model_options_base playhouse/tests/test_models.py::TestModelOptionInheritance::test_custom_options playhouse/tests/test_models.py::TestModelOptionInheritance::test_db_table playhouse/tests/test_models.py::TestModelOptionInheritance::test_option_inheritance playhouse/tests/test_models.py::TestModelOptionInheritance::test_order_by_inheritance playhouse/tests/test_models.py::TestModelOptionInheritance::test_table_name_function playhouse/tests/test_models.py::TestModelInheritance::test_model_inheritance_attrs playhouse/tests/test_models.py::TestModelInheritance::test_model_inheritance_flow playhouse/tests/test_models.py::TestAliasBehavior::test_alias_with_coerce playhouse/tests/test_models.py::TestModelHash::test_hash playhouse/tests/test_models.py::TestDeleteNullableForeignKeys::test_delete playhouse/tests/test_models.py::TestJoinNullableForeignKey::test_no_empty_instances playhouse/tests/test_models.py::TestJoinNullableForeignKey::test_non_null_fk_unselected_fk playhouse/tests/test_models.py::TestJoinNullableForeignKey::test_unselected_fk_pk
README.rst peewee.py
README.rst peewee.py