Skip to content
SQLite

SQLite: database disk image is malformed

database disk image is malformed (the database file is corrupt)

Applies to: SQLite 3.x (examples run on 3.39.2; shell output from 3.50.6)
Last technically reviewed 24 October 2026 on SQLite 3.39.2 (PHP PDO_SQLITE) and the sqlite3 shell 3.50.6
The full message
database disk image is malformed
Other forms of this message
sqlite3 shell (3.50.6), running a script
Runtime error near line 1: database disk image is malformed (11)
PHP PDO
SQLSTATE[HY000]: General error: 11 database disk image is malformed
Python sqlite3 (SQLITE_CORRUPT is raised as sqlite3.DatabaseError, per the CPython source)
sqlite3.DatabaseError: database disk image is malformed
Result code
SQLITE_CORRUPT (11); extended SQLITE_CORRUPT_INDEX (779) when an index no longer matches its table
Product
SQLite library
Versions
SQLite 3.x (examples run on 3.39.2; shell output from 3.50.6)
Last reviewed
24 October 2026

What it means

SQLite found something in the database file that breaks its own file format, so it stopped the statement rather than return or write wrong data. Stop writing to the file, keep a copy of it, check it with PRAGMA integrity_check and recover from the copy or a backup.

A SQLite database is one file made of fixed-size pages (4096 bytes by default) that hold B-trees: one for each table and one for each index, plus the schema on page 1. Each page starts with a small header that says what kind of page it is and where its cells are. When SQLite reads a page whose header, cell pointers or record format make no sense, it returns SQLITE_CORRUPT with this message. It is detected on read, so the damage is usually older than the error.

The error only appears when a statement touches a damaged page. In the lab below, with one table page overwritten, SELECT COUNT(*) still answered (SQLite counted the index, which was intact) while SUM(total) failed, and a damaged index entry made a lookup return no rows without any error until a DELETE needed that entry. So a database can look fine for weeks. When only an index is affected, the extended code is SQLITE_CORRUPT_INDEX (779), which the SQLite documentation says REINDEX may fix if nothing else is damaged.

SQLite does not corrupt its own files without outside help (SQLite FAQ, question 21). The usual causes are copying the file during a write, deleting or separating the -wal or -journal file, power loss on storage that ignores flush requests, network file systems with broken locking, and settings that turn off the protections (synchronous = OFF, journal_mode = OFF). A file that is not a SQLite database at all gives file is not a database instead.

Common causes

  • The file was copied, backed up or synced (cloud folder, backup agent) while a transaction was writing, so the copy mixes old and new pages.
  • The -wal or -journal file next to the database was deleted, renamed or left behind when the database file was moved or copied on its own, so committed changes or the rollback information were lost.
  • A power failure or crash on a disk, virtual machine or USB device that reports writes as done before they are stored, or with PRAGMA synchronous = OFF or journal_mode = OFF.
  • Several computers write the same file over a network share (SMB, NFS) whose file locking does not work reliably.
  • Another part of the program wrote into the file: a stray file handle, a buggy tool, or editing the schema with PRAGMA writable_schema.

Diagnose it

Read-only These statements only read the schema (sqlite_schema and read-only PRAGMA queries) or your own data. They do not change data, settings or the database file, so they are safe to run first.

Run a full integrity check (on a copy)

Copy the database file and any -wal and -journal files while no program has it open, then check the copy. integrity_check reads every page, checks every B-tree and compares each index with its table. It only reads, but on a large file it takes time. PRAGMA integrity_check(orders) limits it to one table and its indexes (SQLite 3.33.0 and later).

PRAGMA integrity_check;
What to look for

ok when no problem is found. Otherwise one row per problem (up to 100 by default). For the damaged index in the lab it returned rows such as row 1500 missing from index ix_orders_customer: index problems only, which REINDEX can repair. Messages that name a tree and page, such as Tree 2 page 12: btreeInitPage() returns error code 11, mean table data is damaged. When the damage is bad enough, the check itself can fail with "database disk image is malformed" (3.39.2 did that for the damaged table page; the 3.50.6 shell printed two problem rows and then the error).

Run the faster quick check

PRAGMA quick_check;
What to look for

The same kind of report as integrity_check, faster, because it does not check that index entries match the table rows or that UNIQUE constraints hold. In the lab it reported *** in database main *** Page 19: btreeInitPage() returns error code 11 for a damaged index page, but returned ok for the index whose entry had been changed, which only integrity_check found. Treat ok from quick_check as "no damaged pages", not as "no problems".

Find the file and its journal mode

Before copying, find the exact file the program uses and whether it is in WAL mode. In WAL mode, committed changes can still be in the -wal file next to the database, so that file must be copied with it and must not be deleted.

PRAGMA database_list;
PRAGMA journal_mode;
What to look for

database_list shows the full path of each open database file. journal_mode returns wal (look for shop.db-wal and shop.db-shm next to it) or delete (a shop.db-journal file may exist after a crash).

Check the copy from the sqlite3 shell

The same check from the command line, on the copy. Output from the sqlite3 shell 3.50.6 for the lab file with a damaged table page:

*** in database main ***\nTree 2 page 12: btreeInitPage() returns error code 11\nwrong # of entries in index ix_orders_customer\nRuntime error near line 1: database disk image is malformed (11)
sqlite3 shop-copy.db "PRAGMA integrity_check;"
What to look for

Tree 2 is the table whose rootpage is 2 in sqlite_schema (here orders), so this table has lost rows, not only an index.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Stop writing and copy every file first

Client or network side

Close the programs that use the database (or stop the service), then copy the database file together with its -wal, -shm and -journal files, if present, to a safe folder. Do every check and recovery attempt on a copy, so a failed attempt never costs you the original.

Caution: Do not delete the -wal or -journal file to "clear" the error. A WAL file can hold committed transactions, and a hot journal is what SQLite needs to roll back a write that was interrupted; deleting either is one of the documented ways to corrupt a database. Also avoid PRAGMA writable_schema edits: changing the schema table by hand can make the file completely unreadable.

Rebuild the indexes when only an index is damaged

Changes data

If integrity_check reports only index problems (row N missing from index ..., wrong # of entries in index ...) or the extended code is SQLITE_CORRUPT_INDEX (779), rebuild the index from the table and check again. In the lab this repaired the damaged index: the check returned ok and the failed DELETE then worked.

Caution: Run it on the copy first. REINDEX rebuilds indexes from table rows, so it cannot bring back rows lost from a damaged table page; if the check still reports tree or page errors, recover the data instead.

REINDEX ix_orders_customer;  -- or REINDEX orders; for every index of the table
PRAGMA integrity_check;

Recover what can be read into a new database (.recover)

Client or network side

The sqlite3 shell's .recover command (SQLite 3.29.0 and later) reads the pages directly and writes SQL for every row it can still find, so it usually gets more back than .dump. Rows it cannot place in a table go into a lost_and_found table. Run it on the copy and load the output into a new file.

Caution: Recovered data can be incomplete or wrong: rows can be missing, deleted rows can reappear and constraints may no longer hold, so compare row counts and important totals before using it. Not every sqlite3 build includes .recover: the Android SDK build of 3.50.6 used here answered "unknown command", so use the official command-line shell from sqlite.org.

sqlite3 shop-copy.db ".recover" > recovered.sql
sqlite3 recovered.db ".read recovered.sql"
sqlite3 recovered.db "PRAGMA integrity_check;"

Fall back to .dump when .recover is not available

Client or network side

.dump reads through normal queries. On the lab copy with one damaged table page, the 3.50.6 shell wrote 1849 of the 2000 rows and ended the script with ROLLBACK; -- due to errors, so loading it unchanged created nothing. Changing that last line to COMMIT; kept the rows it could read.

Caution: Rows on damaged pages are missing from the dump. Compare counts with what you expect, and keep the copy of the damaged file.

sqlite3 shop-copy.db ".dump" > dump.sql
-- edit the last line of dump.sql from ROLLBACK; -- due to errors  to  COMMIT;
sqlite3 recovered.db ".read dump.sql"

Restore from a backup taken the safe way

Client or network side

If you have a backup from before the damage, restoring it is the only way to be sure of the data; add any later changes you can reconstruct. For future backups, use the shell's .backup command, the backup API in your driver, or VACUUM INTO 'backup.db', which all produce a consistent copy of a live database, instead of copying the file while it may be written.

sqlite3 shop.db ".backup shop-backup.db"

Examples

A damaged table page: one query works, the next fails

Lab file: a throwaway database with an orders table (2000 rows) and an index on customer; then 8 bytes at the start of one table page (page 12, offset 45056) were overwritten. Any statement that reads that page fails; statements that can be answered from other pages still work.

SELECT COUNT(*) FROM orders;  -- answers 2000 (counted from the index)
SELECT SUM(total) FROM orders;  -- has to read every table page
Result
database disk image is malformed

Reproduced on SQLite 3.39.2, 24 October 2026.

An index that no longer matches its table (SQLITE_CORRUPT_INDEX)

Lab file: the same database with one byte of one index entry changed. The lookup through the index silently finds nothing; the DELETE must remove the matching index entry, cannot find it and fails with extended code 779 (SQLITE_CORRUPT_INDEX). REINDEX repaired this file.

SELECT * FROM orders WHERE customer = 'customer 1500';  -- no rows, and no error
DELETE FROM orders WHERE id = 1500;
Result
database disk image is malformed

Reproduced on SQLite 3.39.2, 24 October 2026.

The schema page is damaged, so nothing can be read

Lab file: the page header of page 1, which holds the schema, was overwritten (4 bytes at offset 100). SQLite cannot read the list of tables, so every statement fails, even PRAGMA page_count. Only page-level recovery (.recover) or a backup can help here.

SELECT name FROM sqlite_schema;
Result
database disk image is malformed

Reproduced on SQLite 3.39.2, 24 October 2026.

After a power failure with the journal deleted

Shown as documented in the SQLite documentation (How To Corrupt An SQLite Database File); not reproduced here, because it needs a real power failure or crash during a write followed by deleting the hot journal, and the result depends on which pages were written. Without the journal, SQLite cannot roll back the half-written transaction, so some pages are new and some old.

SELECT * FROM orders;
Result
database disk image is malformed

How to prevent it

Keep the protections on: the default synchronous setting (FULL, or NORMAL with WAL), a rollback journal or WAL, and never journal_mode = OFF for data you care about. Keep the database on a local disk; if several machines need it, use a client/server database instead of sharing one file over the network.

Back up with .backup, the backup API or VACUUM INTO, not by copying a file that may be open. Move or copy the database only while it is closed, and always together with its -wal and -journal files. Run PRAGMA quick_check regularly (and integrity_check when there is time) so damage is found while a good backup still exists.

Common questions

How do I fix "database disk image is malformed" in SQLite?

Stop writing, copy the database with its -wal and -journal files, and run PRAGMA integrity_check on the copy. If only indexes are reported, REINDEX can fix it; otherwise recover the rows with the sqlite3 shell's .recover (or .dump) into a new file, or restore a backup.

Can I delete the -wal or -journal file to make the error go away?

No. The -wal file can contain committed transactions that are not yet in the main file, and a hot journal is needed to undo a write that was interrupted. Deleting either is a documented cause of corruption, so copy them with the database instead.

Why do some queries work when the database is corrupt?

SQLite only notices damage when a statement reads the damaged page. A query that can be answered from other pages, for example a COUNT(*) read from an intact index, still works, and a damaged index can make a lookup return no rows without any error. Run integrity_check to see the whole picture.

What is the difference between integrity_check and quick_check?

Both only read the file. quick_check checks the structure of every page and is faster; integrity_check also checks that every index matches its table and that UNIQUE constraints hold, so it finds problems quick_check misses.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on SQLite 3.39.2 (PHP PDO_SQLITE) and the sqlite3 shell 3.50.6. Messages are the text the SQLite library itself returns (sqlite3_errmsg) for the versions shown.

Still stuck on a SQLite error?

Browse the full SQLite error library, or get hands-on help from an experienced SQL professional.