pgref.dev/sqlite/errors/SQLITE_LOCKED
SQLITE_LOCKEDERRORTier 2 — Caution✅ HIGH confidence

database table is locked

Category: Locking & ConcurrencyVersions: All SQLite versions

What this means

SQLITE_LOCKED (result code 6) is a finer-grained lock conflict than SQLITE_BUSY. It occurs when a specific database object (typically a table) is locked within the same database connection — most commonly when trying to write to a table that a still-open cursor is iterating over, or when a savepoint conflict arises within a single connection.

Why it happens

  1. 1A cursor is still iterating over a SELECT result while a write to the same table is attempted on the same connection
  2. 2An open statement on the connection holds a shared lock on the table being written
  3. 3Shared-cache mode is enabled and two different connections in the same process conflict at the table level

How to reproduce

A cursor over a table is still open when an UPDATE on the same table is attempted on the same connection.

trigger — this will ERROR
import sqlite3
conn = sqlite3.connect(':memory:')
conn.execute('CREATE TABLE t (x INTEGER)')
conn.executemany('INSERT INTO t VALUES (?)', [(i,) for i in range(5)])

cursor = conn.execute('SELECT x FROM t')
conn.execute('UPDATE t SET x = x + 1')  # triggers SQLITE_LOCKED
sqlite3.OperationalError: database table is locked

Fix 1: Fetch all rows before writing

When you need to iterate and then update the same table.

fix
import sqlite3
conn = sqlite3.connect(':memory:')
conn.execute('CREATE TABLE t (x INTEGER)')
conn.executemany('INSERT INTO t VALUES (?)', [(i,) for i in range(5)])

rows = conn.execute('SELECT x FROM t').fetchall()  # materialise first
conn.execute('UPDATE t SET x = x + 1')             # now safe

Why this works

fetchall() forces the statement to read all rows from the B-tree into memory and closes the cursor. With no open read cursor the connection can safely escalate to a write lock on the table.

What not to do

Enable shared-cache mode to "improve performance"

Why it's wrong: Shared-cache mode increases the likelihood of SQLITE_LOCKED errors because table-level locks become visible across connections in the same process.

Version notes

SQLite 3.6.19+Extended result code SQLITE_LOCKED_SHAREDCACHE (262) added to distinguish shared-cache conflicts from same-connection conflicts.

Sources

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

🔧 Source ref: sqlite3.h — SQLITE_LOCKED = 6

📖 Further reading: SQLite shared-cache mode

Confidence assessment

✅ HIGH confidence

Well-documented. The distinction between SQLITE_BUSY and SQLITE_LOCKED is stable and consistently applied by the library.

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 →