benbjohnson/litestream · critical
integrity check failed: %s
Error message
integrity check failed: %s
What it means
The PRAGMA quick_check/integrity_check executed successfully but returned something other than 'ok', meaning the restored database is corrupt or inconsistent. RestoreV3 then deletes the output (and -wal/-shm) files and reports this error. This is a genuine data-integrity failure of the restored artifact.
Source
Thrown at replica.go:1358
}
defer func() { _ = db.Close() }()
var pragma string
switch mode {
case IntegrityCheckQuick:
pragma = "quick_check"
case IntegrityCheckFull:
pragma = "integrity_check"
default:
return fmt.Errorf("unsupported integrity check mode: %d", mode)
}
var result string
if err := db.QueryRowContext(ctx, "PRAGMA "+pragma).Scan(&result); err != nil {
return fmt.Errorf("integrity check: %w", err)
}
if result != "ok" {
return fmt.Errorf("integrity check failed: %s", result)
}
// Clean up -shm and -wal files that SQLite may create during the PRAGMA.
_ = os.Remove(dbPath + "-shm")
_ = os.Remove(dbPath + "-wal")
return nil
}
// findBestV3SnapshotForTimestamp returns the best v0.3.x snapshot for the given timestamp.
// Returns nil if no suitable snapshot exists.
func (r *Replica) findBestV3SnapshotForTimestamp(ctx context.Context, client ReplicaClientV3, timestamp time.Time) (*SnapshotInfoV3, error) {
generations, err := client.GenerationsV3(ctx)
if err != nil {
return nil, fmt.Errorf("list v0.3.x generations: %w", err)
}
if len(generations) == 0 {
return nil, nilView on GitHub (pinned to 4ed7a308f6)
Solutions
- Read the returned message: it names the corruption (e.g. 'malformed database image at page N').
- Re-run the restore — a fresh download may fix a truncated transfer.
- Restore from an earlier or later snapshot/generation with intact WAL segments.
- Verify the replica objects' integrity (sizes/checksums) in the storage console.
- If the source DB is healthy, re-establish replication with litestream reset to produce a clean generation, then restore.
Example fix
// before litestream restore -output db.sqlite /path/db // same corrupt snapshot // after litestream restore -timestamp 2026-09-01T00:00:00Z -output db.sqlite /path/db
Defensive patterns
Strategy: fallback
Try / catch
if err := replica.Restore(ctx, opt); err != nil && strings.Contains(err.Error(), "integrity check failed") {
// retry with an earlier timestamp/generation; keep output paths clean
} Prevention
- Run periodic test restores with IntegrityCheckFull to catch replica corruption early
- Verify object sizes/checksums in storage after uploads
- Never kill litestream mid-upload; use graceful shutdown
- Keep multiple generations so you can fall back to an intact snapshot
When it happens
Trigger: Restore/RestoreV3 with IntegrityCheckQuick or IntegrityCheckFull where the PRAGMA result string != "ok" — e.g. 'malformed database image', page checksum failures after an incomplete snapshot download or corrupt WAL replay.
Common situations: Storage backend returning truncated objects; bit-rot on the replica; a snapshot that was uploaded while the source DB was in an inconsistent state (legacy v0.3.x path); interrupting litestream mid-upload.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- cannot restore, SQLite sidecar path already exists: %s. Use
- cannot access SQLite sidecar path: %w
- remove existing output path: %w
- verify
- read page size: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/4e9cbd0bb78ab793.
Report an issue: GitHub.