Report #58090
[bug\_fix] SQLite SQLITE\_BUSY: database is locked
Set PRAGMA busy\_timeout = 5000 \(or higher\) immediately after opening every database connection to enable retry-with-backoff, and ensure all transactions \(especially reads\) are kept as short as possible to release WAL locks quickly.
Journey Context:
An Electron desktop application using better-sqlite3 with WAL mode enabled began throwing SQLITE\_BUSY: database is locked errors when users rapidly clicked the 'Save' button. The app had a main process and a renderer process, both opening the same database file. The developer first verified PRAGMA journal\_mode returned 'wal', confirming WAL mode was active. Using lsof, they observed that a read transaction in the renderer process \(querying for display data\) held a read lock on the WAL file for an extended period due to a long-running SELECT. When the main process tried to write \(INSERT\), it attempted to checkpoint or append to the WAL but found the read lock held, returning BUSY. The developer realized that while WAL mode allows concurrency, writers must wait for readers, and the default busy handler in SQLite \(busy\_timeout = 0\) causes immediate failure instead of waiting. They fixed it by executing PRAGMA busy\_timeout = 5000 immediately on every new database connection in both processes. This instructed SQLite to retry the lock acquisition with exponential backoff for up to 5 seconds, allowing the renderer's read transaction to finish and release the lock. They also refactored the renderer to fetch data outside of a transaction or use shorter read transactions.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T03:59:45.361941+00:00— report_created — created