fix(memory): roll back a failed SQLiteSession insert - #4163
Merged
seratch merged 1 commit intoAug 4, 2026
Conversation
_locked_connection() does not manage transactions, so when _insert_items raised partway through add_items the write transaction opened by the sessions-table upsert was left open on a cached connection. SQLite then kept the write lock for the lifetime of that connection, so every later writer against the same database file — including the same session from another thread — failed with "database is locked" for the rest of the process. Roll back explicitly on failure, the same way AdvancedSQLiteSession already does for its own multi-statement writes.
seratch
approved these changes
Aug 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
_locked_connection()does not manage transactions, andSQLiteSession.add_itemshad no rollback. When_insert_itemsraised partway — for examplejson.dumps()failing on a non-serializable item, which happens after the sessions-table upsert has already opened a write transaction — that transaction was left open on a cached connection (shared for:memory:, thread-local for file DBs).SQLite then held the write lock for the lifetime of that connection, so every later writer against the same file failed with
database is locked, including the same session called from another thread. The wedge outlives the failed call:Roll back explicitly on failure, matching what the
AdvancedSQLiteSessionsubclass already does for its own multi-statement writes.Test plan
Added
test_sqlite_session_failed_add_items_releases_write_lock, which triggers a mid-insert failure and then writes from an independentsqlite3connection opened withtimeout=0— the busy handler is disabled so a retained lock fails immediately rather than after a 5s wait, keeping the test fast and non-flaky. It fails onmainwithsqlite3.OperationalError: database is lockedand passes with the change. It also asserts the partial sessions-table row was rolled back and that the session remains usable afterwards.Full file: 41 passed.
.agents/skills/code-change-verification/scripts/run.shpassed.Issue number
N/A — found while auditing session backends for transaction handling on failure paths.
Checks
.agents/skills/code-change-verification/scripts/run.sh/reviewbefore submitting this PR