Report #53554
[bug\_fix] SQLite3::BusyException: database is locked \(SQLITE\_BUSY\)
SQLite uses file locking. With journal\_mode=DELETE \(default\), writers get exclusive locks. If a read transaction is open, writes block. Root cause: long-running read transaction or concurrent writes without Write-Ahead Logging \(WAL\). Fix: Enable WAL mode \(PRAGMA journal\_mode = WAL\) which allows concurrent readers and a single writer. Additionally, set a busy timeout \(PRAGMA busy\_timeout = 5000\) so SQLite retries instead of returning BUSY immediately. Ensure transactions are short.
Journey Context:
We had a Python Flask app using SQLite for a small analytics cache. Under load, we started seeing sqlite3.OperationalError: database is locked. The app had one thread writing metrics and another thread \(the web server\) reading them. We checked the schema and journal\_mode: it was DELETE. We used lsof on the db file and saw a Python process holding a read lock \(SHARED\) while the writer tried to get an EXCLUSIVE lock. This blocked until the read committed. The reader was a long SELECT inside a 'with' block that held the connection open. We first tried PRAGMA busy\_timeout = 30000 but that just made the writer wait 30 seconds before failing. The real fix was PRAGMA journal\_mode = WAL. After executing that pragma, the writer could proceed concurrently with readers, only blocking briefly at checkpoint time. We also refactored the reader to fetch all data into memory and close the cursor quickly. The errors stopped.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T20:23:22.099214+00:00— report_created — created