You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Have you searched for related issues? Yes. fix(memory): roll back a failed SQLiteSession insert #4163 fixed exactly this for SQLiteSession.add_items; this issue is that the same defect remains in the five sibling write paths. Also searched rollback, write lock, in_transaction, database is locked.
Describe the bug
#4163 established that a write failing partway through leaves an open transaction on the cached connection, and that "an open write transaction would hold the SQLite write lock for the lifetime of the connection and block every later writer." That fix was applied only to SQLiteSession.add_items.
The same defect is still present in five other write paths:
Method
Stranded write transaction after a failed statement
clear_session is the clearest case: it issues two DELETEs under a single commit, so a failure on the second leaves the first applied inside an open transaction — both a partial mutation and a stranded lock.
AsyncSQLiteSession is the more damaging case. It holds one connection for the entire session (self._connection), so the stranded transaction holds the write lock until the session object is closed. Every later add_items from any writer — including other processes — then blocks or fails with database is locked. One transient OperationalError (disk full, a concurrent writer, a schema change) permanently wedges session persistence for that process.
Debug information
Agents SDK version: 0.19.4 (reproduced on main at 8be468f3)
Related library versions: aiosqlite
Python version: 3.12
Operating system: Windows 11 (not platform specific — this is SQLite transaction semantics)
Model and model provider: none needed
Does the issue reproduce with the latest Agents SDK release? Yes.
Does the issue occur consistently or intermittently? Consistently and deterministically.
Repro steps
The script drops a table from an independent connection so that a statement inside the session's write fails, then checks whether the session's connection is still in a transaction and whether an independent writer can still take the write lock.
The session's only connection sits in an open write transaction. Every subsequent write through that session, and every write from any other connection or process, is blocked until the session is closed.
A failed write rolls back, leaving no partial mutation and no open transaction, and the session stays usable — the behavior #4163 established for add_items. All six rows above should read blocked=False.
Root-cause hypothesis
(hypothesis)_locked_connection() yields a cached connection without managing transactions, so every write path has to roll back for itself. #4163 added that rollback inline to add_items only. Because the rollback obligation belongs to the connection rather than to any single method, a small _rollback_on_failure(conn) guard applied at each _locked_connection() write site would cover all of them from one place.
Proposed scope
Add that guard to both SQLite session modules and use it in every write path. No public API change, no schema change, and no change to which statements are committed — only the failure path differs.
I have a fix with regression tests ready and will open a PR referencing this issue.
Please read this first
SQLiteSession.add_items; this issue is that the same defect remains in the five sibling write paths. Also searchedrollback,write lock,in_transaction,database is locked.Describe the bug
#4163 established that a write failing partway through leaves an open transaction on the cached connection, and that "an open write transaction would hold the SQLite write lock for the lifetime of the connection and block every later writer." That fix was applied only to
SQLiteSession.add_items.The same defect is still present in five other write paths:
SQLiteSession.add_items(fixed in #4163)SQLiteSession.pop_itemSQLiteSession.clear_sessionAsyncSQLiteSession.add_itemsAsyncSQLiteSession.pop_itemAsyncSQLiteSession.clear_sessionclear_sessionis the clearest case: it issues twoDELETEs under a single commit, so a failure on the second leaves the first applied inside an open transaction — both a partial mutation and a stranded lock.AsyncSQLiteSessionis the more damaging case. It holds one connection for the entire session (self._connection), so the stranded transaction holds the write lock until the session object is closed. Every lateradd_itemsfrom any writer — including other processes — then blocks or fails withdatabase is locked. One transientOperationalError(disk full, a concurrent writer, a schema change) permanently wedges session persistence for that process.Debug information
0.19.4(reproduced onmainat8be468f3)aiosqliteRepro steps
The script drops a table from an independent connection so that a statement inside the session's write fails, then checks whether the session's connection is still in a transaction and whether an independent writer can still take the write lock.
Actual behavior
The session's only connection sits in an open write transaction. Every subsequent write through that session, and every write from any other connection or process, is blocked until the session is closed.
Running the same probe across all six methods:
Expected behavior
A failed write rolls back, leaving no partial mutation and no open transaction, and the session stays usable — the behavior #4163 established for
add_items. All six rows above should readblocked=False.Root-cause hypothesis
(hypothesis)
_locked_connection()yields a cached connection without managing transactions, so every write path has to roll back for itself. #4163 added that rollback inline toadd_itemsonly. Because the rollback obligation belongs to the connection rather than to any single method, a small_rollback_on_failure(conn)guard applied at each_locked_connection()write site would cover all of them from one place.Proposed scope
Add that guard to both SQLite session modules and use it in every write path. No public API change, no schema change, and no change to which statements are committed — only the failure path differs.
I have a fix with regression tests ready and will open a PR referencing this issue.