Skip to main content

sqliteproof

Find out which tables survived, not which pages broke.

SQLite's own PRAGMA integrity_check is good at detecting corruption. What it gives you is this:

*** in database main ***
Tree 25 page 35 cell 18: Offset 57005 out of range 239..4092
database disk image is malformed

That's a page number. Nobody stores data by page number. What you actually need to know at 3am is which tables can I still trust, how many rows did I lose, and is this worth restoring from backup.

$ sqliteproof app.db

app.db  —  DAMAGED

  table                        verdict         rows     lost
  ------------------------------------------------------------
  orders                       damaged      392/400        8
      breaks after row 182: database disk image is malformed
  audit_log                    intact       400/400        0
  customers                    intact       400/400        0

  1192 rows read, 8 unreadable.
  Tables marked intact above are safe to export. Restore the damaged
  ones from backup rather than trusting a partial read.

Install

pip install sqliteproof

Python 3.9+. No dependencies — standard library only.

Usage

sqliteproof app.db            # full report
sqliteproof app.db --json     # machine-readable
sqliteproof app.db --quiet    # verdict line only

Exit codes: 0 intact · 1 damaged · 2 unreadable or undetermined. Drops straight into a backup script:

sqliteproof app.db --quiet || echo "corruption detected" | mail -s alert me@example.com

It opens the database read-only

A tool asked to inspect a damaged file must never be able to damage it further. The connection is opened with mode=ro and nothing is written to the database, ever.

Runs entirely on your machine. No network, nothing uploaded.

It will not bluff

verdict meaning
INTACT every table read completely and row counts match
DAMAGED some rows are unreadable — with the table named and the break point located
UNKNOWN the damage prevents a determination

UNKNOWN is never dressed up as clean. A tool that reports a corrupt database as healthy is worse than no tool.

Limitations — read these first

Structural, not semantic. It verifies rows can be read. It cannot detect corruption that produces valid-looking values — a flipped bit inside an integer that still parses is invisible to it.

Row counts come from the same damaged btree. When COUNT(*) itself fails, the expected count is unknown and the verdict degrades to UNKNOWN rather than guessing.

It does not repair anything. It tells you what survived so you can export the good tables and restore the rest. Recovery is a different tool.

v0.1.0. Tested against databases built by SQLite and damaged at known page offsets: 3/3 corrupted databases localised to the correct table, 0 false alarms, 0 false-clean. That corpus is deliberate byte corruption, which is one failure mode among several — real corruption also arrives via truncated files, interrupted writes, and failing disks.

Tests

python sqliteproof/tests/corrupt.py   # build the corpus
python sqliteproof/tests/score.py     # score localisation vs ground truth

Ground truth comes from SQLite's own page allocation: tables are built one at a time and the pages added between "before" and "after" belong to that table. The file format isn't my invention and the damage lands where SQLite chose to put the data.

If you got here from an error message

These are the messages SQLite prints when a database has gone bad. If you pasted one into a search engine and landed here, this is what each one means and what this tool does about it.

what SQLite told you what it means what sqliteproof adds
database disk image is malformed The B-tree structure is damaged somewhere. SQLite will not say where. Which tables still read completely, which are damaged, and how many rows are gone
Tree N page M cell K: Offset … out of range PRAGMA integrity_check found a specific broken page Translates the page into the table that owns it
malformed database schema The schema table itself is damaged Reports UNREADABLE rather than guessing
no such table after a crash Possibly a lost schema page Reads what is still there, read-only, without writing

Two things worth knowing before you do anything else:

  1. Copy the file first. Work on the copy. Several recovery approaches write to the database, and a failed repair on your only copy is unrecoverable. sqliteproof itself opens the file read-only and never writes, which is why it is safe to run first.
  2. A clean report is not a guarantee of correct data. It means every row was structurally readable. Corruption that produces valid-looking values cannot be detected this way, and this tool says so rather than implying otherwise.

If you need to repair rather than assess, SQLite's own .recover command in the sqlite3 shell is the right next step. This tool tells you whether that is worth doing and what you stand to lose — it does not replace it.

Related

statementproof — the same idea for bank statement PDFs. Most converters hand you a CSV and leave you to trust it; statementproof checks the extracted rows against the statement's own opening and closing balances and names the row where the running total stops following.

License

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqliteproof-0.1.1.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqliteproof-0.1.1-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file sqliteproof-0.1.1.tar.gz.

File metadata

  • Download URL: sqliteproof-0.1.1.tar.gz
  • Upload date:
  • Size: 11.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for sqliteproof-0.1.1.tar.gz
Algorithm Hash digest
SHA256 a3e16151437e394525a7aec06290c610b3cb1f1bc32f6cd1c06f2dd587eba4c3
MD5 b4113549c8cfbfc38c4be2937662609f
BLAKE2b-256 de1827cf0e9dbb6c7e97a4dc1255e2f913f083137e87e01d53d000b2c3643683

See more details on using hashes here.

File details

Details for the file sqliteproof-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: sqliteproof-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 10.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for sqliteproof-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f69e4cd4fbdedf316208b54cf58610335d9dfb43d316372f6dea21cd4a59db50
MD5 033349871af591c97723a93058711903
BLAKE2b-256 e43a45e691994f397b25fb2b5832b44b68c53e66302c622041e1551ca364c91e

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page