attempt to write a readonly database
SQLITE_READONLY (result code 8) is returned when SQLite attempts a write operation on a database that was opened in read-only mode, or whose underlying file has OS-level read-only permissions. The check is performed before any disk I/O so the database is never partially modified.
- 1The database file or its containing directory has read-only OS permissions (chmod 444)
- 2The connection was opened with the SQLITE_OPEN_READONLY flag
- 3The database is on a read-only filesystem (e.g., CD-ROM, read-only NFS mount)
- 4The WAL file or shared-memory file exists but is not writable while the database itself is readable
A database file is made read-only at the OS level and then a write is attempted.
import sqlite3, os, stat
# Create and populate the database
conn = sqlite3.connect('/tmp/demo.db')
conn.execute('CREATE TABLE t (x INTEGER)')
conn.commit()
conn.close()
# Make it read-only
os.chmod('/tmp/demo.db', stat.S_IRUSR | stat.S_IRGRP)
# Attempt to write — triggers SQLITE_READONLY
conn = sqlite3.connect('/tmp/demo.db')
conn.execute('INSERT INTO t VALUES (1)')expected output
sqlite3.OperationalError: attempt to write a readonly database
Fix 1
Restore write permissions
WHEN When the file should be writable but permissions were accidentally changed.
import os, stat
os.chmod('/tmp/demo.db', stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP)Why this works
SQLite checks the OS writability of the database file and its parent directory before opening a write transaction. Restoring write permission (mode 0644 or stricter) allows the library to acquire the write lock.
Fix 2
Open a copy of the database for writing
WHEN When the source database must remain read-only (e.g., shipped with an app).
import sqlite3, shutil
shutil.copy('/assets/readonly.db', '/data/user.db')
conn = sqlite3.connect('/data/user.db')
conn.execute('INSERT INTO t VALUES (1)')
conn.commit()Why this works
Copying to a writable location gives the application a mutable working copy while keeping the original read-only asset intact. Common pattern for mobile apps shipping a pre-populated SQLite database.
✕ Open the database with sqlite3.connect() and ignore the SQLITE_READONLY error
Silent swallowing of write errors means data changes are never persisted, leading to data loss and confusing application state.
SQLITE_READONLY_ROLLBACK (264) extended code added — emitted when a hot journal exists but the database is read-only, preventing rollback of an interrupted transaction.
Content generated with AI assistance and reviewed for accuracy. Found an error? hello@errcodes.dev