Report #58341
[bug\_fix] sqlite3.OperationalError: database is locked
Set \`PRAGMA busy\_timeout = 30000;\` \(30 seconds\) immediately after opening each database connection. This causes SQLite to retry the operation with exponential backoff rather than returning SQLITE\_BUSY immediately. Additionally, ensure WAL \(Write-Ahead Logging\) mode is enabled \(\`PRAGMA journal\_mode = WAL;\`\) to allow readers and writers to proceed concurrently without locking the entire database file.
Journey Context:
A developer migrates a single-user desktop application to a web API using Flask with multiple Gunicorn workers \(4 processes\) accessing a single SQLite database file. Under light load, everything works. Under moderate concurrency, the application begins throwing 'sqlite3.OperationalError: database is locked' errors on write operations. The developer checks that the file is not read-only and that no other processes are accessing it. They examine the SQLite documentation and learn that the default \`busy\_timeout\` is 0, meaning SQLite returns SQLITE\_BUSY immediately if the database is locked, rather than waiting. They also discover that without WAL mode, a writer must obtain an exclusive lock on the entire database file. The fix involves two changes: first, executing \`PRAGMA busy\_timeout = 30000;\` immediately after opening each connection to enable retry logic. Second, enabling WAL mode \(\`PRAGMA journal\_mode = WAL;\`\) which allows readers to continue operating without blocking writers, and vice versa, significantly reducing lock contention.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T04:24:59.318305+00:00— report_created — created