Skip to content

fix: disable implicit transactions in sqlite#102

Merged
QueryPlanner merged 2 commits into
mainfrom
fix/sqlite-transaction-bug
Jun 1, 2026
Merged

fix: disable implicit transactions in sqlite#102
QueryPlanner merged 2 commits into
mainfrom
fix/sqlite-transaction-bug

Conversation

@QueryPlanner
Copy link
Copy Markdown
Owner

What

Fix SQLite transaction error by setting isolation_level=None when creating database connections.

Why

The application was experiencing sqlite3.OperationalError: cannot start a transaction within a transaction errors when logging workouts. This occurred because:

  1. aiosqlite connections use Python's default isolation level, which creates implicit transactions
  2. When code explicitly calls BEGIN to start a manual transaction, SQLite rejects it if an implicit transaction is already active
  3. This created intermittent failures depending on connection state from previous operations

How

  • Set isolation_level=None parameter when creating aiosqlite connection in src/blacki/storage/sqlite.py
  • This disables implicit transactions, giving full manual control over transaction boundaries
  • Allows BEGIN, COMMIT, and ROLLBACK statements to work correctly

Tests

  • All 831 existing tests pass
  • Code coverage remains at 100%
  • Linting and type checking pass
  • Manual verification: The create_session method in workout storage uses explicit transactions and will now work correctly

- Set isolation_level=None when creating aiosqlite connection
- Prevents 'cannot start a transaction within a transaction' error
- Allows manual transaction control with BEGIN/COMMIT/ROLLBACK
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the SQLite connection creation in src/blacki/storage/sqlite.py to use isolation_level=None. The reviewer points out that this enables autocommit mode, which silently disables connection.commit() and connection.rollback(). This will break transaction handling in other parts of the application, such as src/blacki/workouts/storage.py, which still rely on those methods. The reviewer recommends using explicit SQL statements for committing and rolling back transactions.

path.parent.mkdir(parents=True, exist_ok=True)

conn = await aiosqlite.connect(path)
conn = await aiosqlite.connect(path, isolation_level=None)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Setting isolation_level=None puts the connection into autocommit mode and disables Python's automatic transaction management. While this is the correct way to handle manual transactions, it has a critical side effect: calling connection.commit() and connection.rollback() on the connection object becomes a silent no-op in Python's sqlite3 (and thus aiosqlite).

In src/blacki/workouts/storage.py (line 116), create_session starts a manual transaction with BEGIN but attempts to commit/rollback using await self._conn.commit() and await self._conn.rollback(). With isolation_level=None, these calls will do nothing, leaving the transaction open indefinitely and causing subsequent operations to fail with database locks or transaction errors.

To fix this, you must update create_session to use explicit SQL statements for committing and rolling back:

await self._conn.execute("COMMIT")
await self._conn.execute("ROLLBACK")
Suggested change
conn = await aiosqlite.connect(path, isolation_level=None)
# isolation_level=None disables implicit transactions (autocommit mode).
# Note: Use execute("COMMIT") / execute("ROLLBACK") instead of conn.commit() / conn.rollback().
conn = await aiosqlite.connect(path, isolation_level=None)

- Replace conn.commit()/rollback() with execute('COMMIT'/'ROLLBACK')
- Required when isolation_level=None (autocommit mode)
- Update all test fixtures to use isolation_level=None
- Update log message to indicate autocommit mode
@QueryPlanner QueryPlanner merged commit e52c370 into main Jun 1, 2026
1 check passed
@QueryPlanner QueryPlanner deleted the fix/sqlite-transaction-bug branch June 1, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant