Report #54643
[bug\_fix] sqlite3.OperationalError: database is locked \(SQLITE\_BUSY\)
Enable Write-Ahead Logging \(WAL\) mode via \`PRAGMA journal\_mode=WAL;\` and set a busy timeout handler via \`PRAGMA busy\_timeout = 5000;\` \(milliseconds\). Root cause: the default DELETE journal mode requires an exclusive lock on the entire database file for writes, causing \`SQLITE\_BUSY\` when another connection \(even a reader\) holds a lock. WAL mode allows concurrent reads during writes.
Journey Context:
A developer deploys a small internal tool using Python Flask and SQLite. The app uses the default connection settings. When two users click 'save' simultaneously, one gets a 500 error: \`sqlite3.OperationalError: database is locked\`. The developer inspects the SQLite file and sees a \`-journal\` file lingering. They read the SQLite locking docs and realize the default rollback journal requires an exclusive lock on the entire database for the duration of the write transaction. They switch to WAL mode by executing \`PRAGMA journal\_mode=WAL;\` on the connection. Now writes append to the \`-wal\` file instead of overwriting the main db, allowing readers to continue using the main file. However, they still get rare \`database is locked\` errors under very heavy load. They add \`PRAGMA busy\_timeout = 5000;\`, which tells SQLite to retry the write for up to 5 seconds if a lock is held, rather than returning SQLITE\_BUSY immediately. The combination eliminates all lock errors while maintaining concurrent read performance.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T22:12:54.870128+00:00— report_created — created