Diagnostics and recovery
Keep the source and its SQLite sidecars together. Stop application writers before
recovery and write the result to a new path. Neither repair nor recovery replaces
the source or overwrites an existing destination. Existing destination -wal,
-shm and -journal files also prevent publication.
Check an existing file
boxdb check data.db --quickboxdb check data.db --full --jsonChecks never create a missing database or initialize BoxDB metadata. Binary checks use a read-only connection and one read transaction, including committed WAL contents. They do not change the journal mode or checkpoint the database; SQLite may manage shared-memory coordination files for a WAL reader.
Quick mode checks SQLite structure and BoxDB metadata. Full mode additionally checks index consistency, foreign keys, logical column values and BLOB encodings in ordinary main-database tables. YAML must be parsed and restored even in quick mode. JSON is validated as an opaque document; no SQL JSON processing is used.
A report has status: valid | invalid | incomplete, a complete flag, performed
checks and issues. valid means the performed checks found no problems, not that
every original value is correct. A changed but still valid value can go
undetected. complete: false means validation stopped or some checks could not
run, including when metadata is unusable. Locked or inaccessible database pages
are not classified as proven corruption. The CLI exits unsuccessfully when the
check does not pass. With --json, reports go to stdout and errors to stderr.
Issues identify tables, columns, rowids and YAML document/line locations when available. Serialized rowids are decimal strings to preserve 64-bit precision. Value errors do not include cell contents. SQLite structural diagnostics retain the engine’s message. Reports are bounded to 1,000 value/foreign-key issues; SQLite’s structural check has its own error limit.
Rebuild indexes
boxdb repair data.db repaired.db --rebuild-indexes --jsonRepair copies readable table data through BoxDB’s engine and rebuilds indexes in a new binary database. It preserves accessible rowids, logical metadata, AUTOINCREMENT sequences, views and triggers, and recomputes generated columns. Application triggers are created after loading rows. Virtual tables are rejected. Unusable schemas, unreadable table data or an invalid final database abort repair. This operation does not need the source indexes to be readable.
Salvage available data
boxdb recover damaged.db recovered.db --jsonboxdb recover damaged.yaml recovered.yaml --format readable --jsonBinary recovery uses SQLite’s recovery extension with BoxDB’s native codec and
bundled functions. It excludes freelist pages to reduce resurrection of deleted
records. Records that cannot be assigned to a table may appear in lost_and_found.
Recovered content can be missing or altered; virtual-table content and damaged
schema objects are not guaranteed to survive. See SQLite’s
recovery limitations.
YAML recovery reads independently delimited documents, requires a valid header,
and restores the available schema and metadata without inferring missing types.
It skips malformed or rejected row documents and creates application triggers
after rows. Rejected fragments are retained verbatim in <destination>.rejected,
with document numbers and source line numbers. This file contains source data;
the report only lists locations and reasons. Damage to document boundaries or
required schema/metadata can prevent recovery. Orphaned rows are retained and
reported by the final foreign-key check.
Every recovery returns a full check of its output and loss_possible: true, even
if that check passes. recovered_rows counts ordinary application rows, including
lost_and_found; it cannot establish how many rows were lost. A binary result
that fails checks is retained for further inspection and the CLI exits with an
error. Readable output is published only if validation and conversion succeed.
Review rejected documents, warnings and application invariants before use.
Application interfaces
Rust uses the same operations:
use boxdb::{CheckMode, Database, Format};
let check = Database::check_file("data.db", CheckMode::Full)?;let repair = Database::repair_file("data.db", "repaired.db")?;let salvage = Database::recover_file("damaged.db", "recovered.db", Format::Binary)?;# Ok::<(), boxdb::Error>(())TypeScript exposes BoxDB.checkFile(path, "full"),
BoxDB.repairFile(source, destination) and
BoxDB.recoverFile(source, destination, "binary") as promises. These file
operations run on native workers independently of open client connections.
Go exposes CheckFile(path, CheckFull), RepairFile(source, destination) and
RecoverFile(source, destination, Binary) as blocking functions returning a
report and an error. File maintenance has no per-call cancellation option.
For all clients, a returned report means the operation ran; inspect status and
complete before treating the file as valid. For example:
import { BoxDB } from "@boxdb/client";
const report = await BoxDB.checkFile("data.db", "full");if (report.status !== "valid" || !report.complete) { console.error(report.issues);}Read operation state and unusable connections before implementing retries or pool recovery. A failed write can have an unknown outcome; reconnecting does not establish whether it was applied.
For recovery from an intact external copy, use
Litestream restoration, then run boxdb check restored.db --full.
BoxDB does not manage backup scheduling, remote storage or retention. Normal
database opening retains its create-if-missing behavior.