v4: Task schedule lost and / or "cannot commit transaction" error from SQLite

Author: JacobHayesCreated Mar 6, 2025Updated Dec 1, 2025
Labelsbug

Things to check first

  • I have checked that my issue does not already have a solution in the FAQ

  • I have searched the existing issues and didn't find my bug already reported there

  • I have checked that my bug is still present in the latest release

Version

v4 @ #1030 (master crashes with the KeyError fixed in #1030)

What happened?

Running the script below ends up with one of two things happening, either it:

  • stops scheduling jobs after running for a bit (0-3 minutes?)
    • you'll eventually notice no more prints from the jobs arrive.
    • this is not related to max_concurrent_jobs - there's only 1 job running at a time here
  • crashes with cannot commit transaction - SQL statements in progress from SQLite
    • some searching mentioned That error can happen when the values returned by a RETURNING clause are not used, but I'm not sure if there are other triggers.
    • perhaps we return early or have some awaits in the middle of iterating over a result set that give other tasks time to run queries and conflict
full stacktrace

I had a couple extra prints scattered throughout the code, so the exact line numbers here may be off by a few:

Scheduler crashed
  + Exception Group Traceback (most recent call last):
  |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/_schedulers/async_.py", line 859, in run_until_stopped
  |     async with create_task_group() as task_group:
  |                ~~~~~~~~~~~~~~~~~^^
  |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 767, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     )
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/_schedulers/async_.py", line 1178, in _process_jobs
    |     await wakeup_event.wait()
    |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 1766, in wait
    |     await self._event.wait()
    |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/asyncio/locks.py", line 213, in wait
    |     await fut
    | asyncio.exceptions.CancelledError: Cancelled by cancel scope 1072e6750
    |
    | During handling of the above exception, another exception occurred:
    |
    | Exception Group Traceback (most recent call last):
    |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/_schedulers/async_.py", line 1130, in _process_jobs
    |     async with AsyncExitStack() as exit_stack:
    |                ~~~~~~~~~~~~~~^^
    |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 768, in __aexit__
    |     raise exc
    |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 751, in __aexit__
    |     cb_suppress = await cb(*exc_details)
    |                   ^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 767, in __aexit__
    |     raise BaseExceptionGroup(
    |         "unhandled errors in a TaskGroup", self._exceptions
    |     )
    | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1142, in _commit_impl
      |     self.engine.dialect.do_commit(self.connection)
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/default.py", line 703, in do_commit
      |     dbapi_connection.commit()
      |     ~~~~~~~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 296, in commit
      |     self._handle_exception(error)
      |     ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 323, in _handle_exception
      |     raise error
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 294, in commit
      |     self.await_(self._connection.commit())
      |     ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 132, in await_only
      |     return current.parent.switch(awaitable)  # type: ignore[no-any-return,attr-defined] # noqa: E501
      |            ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 196, in greenlet_spawn
      |     value = await result
      |             ^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/aiosqlite/core.py", line 155, in commit
      |     await self._execute(self._conn.commit)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/aiosqlite/core.py", line 122, in _execute
      |     return await future
      |            ^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/aiosqlite/core.py", line 105, in run
      |     result = function()
      | sqlite3.OperationalError: cannot commit transaction - SQL statements in progress
      |
      | The above exception was the direct cause of the following exception:
      |
      | Traceback (most recent call last):
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/_schedulers/async_.py", line 1126, in extend_job_leases
      |     await self.data_store.extend_acquired_job_leases(
      |         self.identity, job_ids, self.lease_duration
      |     )
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/datastores/sqlalchemy.py", line 1117, in extend_acquired_job_leases
      |     async for attempt in self._retry():
      |     ...<11 lines>...
      |                 await self._execute(conn, update)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/asyncio/__init__.py", line 166, in __anext__
      |     do = await self.iter(retry_state=self._retry_state)
      |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/asyncio/__init__.py", line 153, in iter
      |     result = await action(retry_state)
      |              ^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/_utils.py", line 99, in inner
      |     return call(*args, **kwargs)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/__init__.py", line 398, in <lambda>
      |     self._add_action_func(lambda rs: rs.outcome.result())
      |                                      ~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/concurrent/futures/_base.py", line 449, in result
      |     return self.__get_result()
      |            ~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/concurrent/futures/_base.py", line 401, in __get_result
      |     raise self._exception
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/datastores/sqlalchemy.py", line 1119, in extend_acquired_job_leases
      |     async with self._begin_transaction() as conn:
      |                ~~~~~~~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 221, in __aexit__
      |     await anext(self.gen)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/datastores/sqlalchemy.py", line 221, in _begin_transaction
      |     async with AsyncExitStack() as exit_stack:
      |                ~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 768, in __aexit__
      |     raise exc
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 751, in __aexit__
      |     cb_suppress = await cb(*exc_details)
      |                   ^^^^^^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 221, in __aexit__
      |     await anext(self.gen)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/ext/asyncio/engine.py", line 1065, in begin
      |     async with conn.begin():
      |                ~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/ext/asyncio/engine.py", line 1418, in __aexit__
      |     await greenlet_spawn(self._proxied.__exit__, type_, value, traceback)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 201, in greenlet_spawn
      |     result = context.throw(*sys.exc_info())
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/util.py", line 147, in __exit__
      |     with util.safe_reraise():
      |          ~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
      |     raise exc_value.with_traceback(exc_tb)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/util.py", line 145, in __exit__
      |     self.commit()
      |     ~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 2629, in commit
      |     self._do_commit()
      |     ~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 2734, in _do_commit
      |     self._connection_commit_impl()
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 2705, in _connection_commit_impl
      |     self.connection._commit_impl()
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1144, in _commit_impl
      |     self._handle_dbapi_exception(e, None, None, None, None)
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 2352, in _handle_dbapi_exception
      |     raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1142, in _commit_impl
      |     self.engine.dialect.do_commit(self.connection)
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/engine/default.py", line 703, in do_commit
      |     dbapi_connection.commit()
      |     ~~~~~~~~~~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 296, in commit
      |     self._handle_exception(error)
      |     ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 323, in _handle_exception
      |     raise error
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py", line 294, in commit
      |     self.await_(self._connection.commit())
      |     ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 132, in await_only
      |     return current.parent.switch(awaitable)  # type: ignore[no-any-return,attr-defined] # noqa: E501
      |            ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 196, in greenlet_spawn
      |     value = await result
      |             ^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/aiosqlite/core.py", line 155, in commit
      |     await self._execute(self._conn.commit)
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/aiosqlite/core.py", line 122, in _execute
      |     return await future
      |            ^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/aiosqlite/core.py", line 105, in run
      |     result = function()
      | sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) cannot commit transaction - SQL statements in progress
      | (Background on this error at: https://sqlalche.me/e/20/e3q8)
      +------------------------------------
  + Exception Group Traceback (most recent call last):
  |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 751, in __aexit__
  |     cb_suppress = await cb(*exc_details)
  |                   ^^^^^^^^^^^^^^^^^^^^^^
  |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 767, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     )
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.scratch/repro_sqlalchemy_deleted_schedule.py", line 29, in main
    |     await scheduler.run_until_stopped()
    |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/_schedulers/async_.py", line 859, in run_until_stopped
    |     async with create_task_group() as task_group:
    |                ~~~~~~~~~~~~~~~~~^^
    |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 767, in __aexit__
    |     raise BaseExceptionGroup(
    |         "unhandled errors in a TaskGroup", self._exceptions
    |     )
    | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
    +-+---------------- 1 ----------------
      | Exception Group Traceback (most recent call last):
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/_schedulers/async_.py", line 1130, in _process_jobs
      |     async with AsyncExitStack() as exit_stack:
      |                ~~~~~~~~~~~~~~^^
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 768, in __aexit__
      |     raise exc
      |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/contextlib.py", line 751, in __aexit__
      |     cb_suppress = await cb(*exc_details)
      |                   ^^^^^^^^^^^^^^^^^^^^^^
      |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 767, in __aexit__
      |     raise BaseExceptionGroup(
      |         "unhandled errors in a TaskGroup", self._exceptions
      |     )
      | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
      +-+---------------- 1 ----------------
        | Traceback (most recent call last):
        |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/_schedulers/async_.py", line 1126, in extend_job_leases
        |     await self.data_store.extend_acquired_job_leases(
        |         self.identity, job_ids, self.lease_duration
        |     )
        |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/datastores/sqlalchemy.py", line 1117, in extend_acquired_job_leases
        |     async for attempt in self._retry():
        |     ...<11 lines>...
        |                 await self._execute(conn, update)
        |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/asyncio/__init__.py", line 166, in __anext__
        |     do = await self.iter(retry_state=self._retry_state)
        |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/asyncio/__init__.py", line 153, in iter
        |     result = await action(retry_state)
        |              ^^^^^^^^^^^^^^^^^^^^^^^^^
        |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/_utils.py", line 99, in inner
        |     return call(*args, **kwargs)
        |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/.venv/lib/python3.13/site-packages/tenacity/__init__.py", line 398, in <lambda>
        |     self._add_action_func(lambda rs: rs.outcome.result())
        |                                      ~~~~~~~~~~~~~~~~~^^
        |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/concurrent/futures/_base.py", line 449, in result
        |     return self.__get_result()
        |            ~~~~~~~~~~~~~~~~~^^
        |   File "/Users/jacobhayes/.local/share/uv/python/cpython-3.13.1-macos-aarch64-none/lib/python3.13/concurrent/futures/_base.py", line 401, in __get_result
        |     raise self._exception
        |   File "/Users/jacobhayes/src/github.com/agronholm/apscheduler/src/apscheduler/datastores/sqlalchemy.py", line 1119, in extend_acquired_job_leases
        |     async with self._begin_transaction() as conn: