Report #9673
[bug\_fix] database is locked \(SQLITE\_BUSY\) in concurrent SQLite access
Execute PRAGMA journal\_mode=WAL immediately after opening the database to enable Write-Ahead Logging, allowing concurrent reads and a single writer without file locking conflicts.
Journey Context:
Developer builds a FastAPI application using SQLite for simplicity. Works perfectly in local single-process testing. Deploys to production with 4 uvicorn workers. Immediately sees random 500 errors: "sqlite3.OperationalError: database is locked". Initial research suggests adding a busy timeout \(PRAGMA busy\_timeout=5000\), which reduces errors but they still occur under write-heavy load. Developer inspects the database file and notices -journal files appearing and disappearing. Reading the SQLite file locking documentation, discovers that the default DELETE journal mode requires an exclusive lock on the entire database file for any write operation. When multiple workers attempt simultaneous writes, they fight over the exclusive lock, causing SQLITE\_BUSY. The definitive fix is switching to WAL \(Write-Ahead Logging\) mode by executing PRAGMA journal\_mode=WAL on each connection. In WAL mode, writes append to a separate -wal file, and readers access the original database file using the last committed state. This allows concurrent reads to proceed without blocking, and writes only require brief locks to sync the WAL. The change is persistent in the database file and requires no application logic changes beyond the initial PRAGMA execution.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T08:46:19.959871+00:00— report_created — created