Report #6264
[bug\_fix] SQLite "database is locked" \(SQLITE\_BUSY / error code 5\)
In SQLite's WAL \(Write-Ahead Logging\) mode, the default since 3.7.0, a writer needs an exclusive lock briefly at commit to write the WAL. If another connection holds a read transaction open \(preventing WAL checkpoint\) or another writer is committing, subsequent writers get SQLITE\_BUSY. The default busy timeout is 0 \(immediate failure\). The fix is to set PRAGMA busy\_timeout = 5000; \(milliseconds\) immediately after opening each connection, causing SQLite to retry the lock acquisition with exponential backoff for 5 seconds before failing. For write-heavy workloads, additionally use BEGIN IMMEDIATE when starting write transactions to acquire the write lock at the start \(reducing contention at commit time\) rather than the default DEFERRED mode which upgrades at commit.
Journey Context:
You're building an Electron desktop app with better-sqlite3 for local data storage. Users report intermittent "database is locked" errors when rapidly saving settings. You reproduce it by clicking save 10 times quickly. You check the database: it's in WAL mode \(default\). You examine the connections: the main thread and a worker thread both access the same DB file. The errors happen when one thread is in the middle of a write while the other tries to commit. You check the SQLite docs and find that the default busy handler is 0. You add db.pragma\('busy\_timeout = 5000'\) on initialization. The errors decrease but still occur under extreme rapid fire. You investigate further and learn about BEGIN IMMEDIATE: by default, BEGIN DEFERRED doesn't acquire the write lock until the first write statement, causing a rush at commit time. You change your write functions to use db.prepare\('BEGIN IMMEDIATE'\) followed by the statements and COMMIT. This acquires the exclusive lock immediately, eliminating the race at commit. Combined with busy\_timeout, the "database is locked" errors disappear completely even under stress testing.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T23:40:34.989688+00:00— report_created — created