pgref.dev/sqlite/errors/SQLITE_BUSY_RECOVERY
SQLITE_BUSY_RECOVERYWARNINGTier 2 — Caution⚠️ MEDIUM confidence

Busy: another connection is recovering WAL

Category: LockingVersions: 3.7.0+

🔴 Production Risk Error

Low — transient; resolves once WAL recovery finishes.

What this means

SQLITE_BUSY_RECOVERY (261) is an extended code returned when a database is in WAL mode and another connection is currently performing crash recovery (replaying the WAL). The caller should wait and retry.

Why it happens

  1. 1Application restarted after a crash; first connection to open the WAL database is performing recovery.
  2. 2Another process is replaying uncommitted WAL frames after an unclean shutdown.

How to reproduce

WAL-mode database open after an unclean shutdown with concurrent connections.

trigger — this will ERROR
import sqlite3, time
for attempt in range(5):
    try:
        conn = sqlite3.connect('my.db', timeout=5)
        conn.execute('SELECT 1')
        break
    except sqlite3.OperationalError as e:
        if 'database is locked' in str(e):
            time.sleep(0.5)
Transient; retries succeed once recovery completes.

Fix 1

Why this works

Retry with exponential backoff — recovery completes quickly in most cases.

Fix 2

Why this works

Set a reasonable connection timeout: sqlite3.connect("my.db", timeout=10)

Version notes

Sources

📚 Official docs: https://www.sqlite.org/rescode.html#busy_recovery

🔧 Source ref: sqlite3.h — SQLITE_BUSY_RECOVERY = 261

📖 Further reading: WAL mode

Confidence assessment

⚠️ MEDIUM confidence

Stable.

See also

⚙️ This error reference was generated with AI assistance and reviewed for accuracy. Examples are provided to illustrate common scenarios and may not cover every case. Always test fixes in a development environment before applying to production. Spotted an error? Suggest a correction →