Report #41321
[bug\_fix] sqlite3.OperationalError: database is locked \(SQLITE\_BUSY in WAL mode\)
Set PRAGMA busy\_timeout = 5000 \(milliseconds\) so writers wait instead of failing immediately, and ensure long-running read transactions are committed frequently or use PRAGMA read\_uncommitted = 1 for analytics to prevent checkpoint starvation.
Journey Context:
A Flask app with background CSV export tasks starts throwing 'database is locked' errors under load. The app uses WAL mode, so reads shouldn't block writes. Investigation shows the export opens a transaction, iterates a 10M row table with a cursor, taking 15 minutes. During this, the -wal file grows to 2GB. Checkpoints \(which move data from WAL to main db\) are blocked because SQLite cannot checkpoint while a reader has an old snapshot. New writers try to write, but the WAL is full and can't be checkpointed, resulting in SQLITE\_BUSY. The fix involves setting a busy timeout so writers wait, and refactoring the export to fetch data in smaller chunks with frequent commits, or using a separate read-only replica connection with read\_uncommitted pragma.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T23:49:59.088984+00:00— report_created — created