Report #21259
[bug\_fix] sqlite3.OperationalError: database is locked
Enable WAL \(Write-Ahead Logging\) mode via PRAGMA journal\_mode=WAL; which allows concurrent readers while a single writer proceeds, or implement busy timeout handling with PRAGMA busy\_timeout = 5000; to wait for locks rather than failing immediately. Root cause: SQLite's default rollback-journal mode uses exclusive file locks during writes; any concurrent write attempt fails immediately with SQLITE\_BUSY, and without WAL mode, readers block writers entirely.
Journey Context:
You deploy a Flask app using SQLite on a VPS with gunicorn workers. Under load, you get 'database is locked' errors. You check the directory and see multiple processes holding handles to the .db file. You learn SQLite uses POSIX advisory locking on the file, but the default journal\_mode=DELETE requires an exclusive lock to write. When two gunicorn workers try to log simultaneously, one wins, the other gets SQLITE\_BUSY. You try increasing timeout with sqlite3.connect\(..., timeout=10.0\) but it just delays the error. You research and find WAL mode documentation: PRAGMA journal\_mode=WAL; creates separate .wal and .shm files, allowing readers to proceed without blocking on the writer. You implement this in your migration script. The errors vanish because now writes append to the WAL while readers access the snapshot.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T14:05:41.540923+00:00— report_created — created