{"record":{"id":"3f2b0201b598768d","repo":"rqlite/rqlite","slug":"installed-db-file-is-not-a-valid-sqlite-file","errorCode":null,"errorMessage":"installed DB file is not a valid SQLite file","messagePattern":"installed DB file is not a valid SQLite file","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"snapshot/sink_full.go","lineNumber":33,"sourceCode":"\nvar (\n\t// ErrSinkOpen indicates that the sink is already open.\n\tErrSinkOpen = errors.New(\"snapshot sink already open\")\n\n\t// ErrSinkNotOpen indicates that the sink is not open.\n\tErrSinkNotOpen = errors.New(\"snapshot sink not open\")\n\n\t// ErrUnexpectedData indicates that the caller wrote more bytes than expected.\n\tErrUnexpectedData = errors.New(\"no more data expected\")\n\n\t// ErrIncomplete indicates Close() was called before all bytes were written.\n\tErrIncomplete = errors.New(\"snapshot install incomplete\")\n\n\t// ErrHeaderInvalid indicates the header is invalid.\n\tErrHeaderInvalid = errors.New(\"snapshot install header invalid\")\n\n\t// ErrInvalidSQLiteFile indicates the installed DB file is not a valid SQLite file.\n\tErrInvalidSQLiteFile = errors.New(\"installed DB file is not a valid SQLite file\")\n\n\t// ErrInvalidWALFile indicates the installed WAL file is not a valid SQLite WAL file.\n\tErrInvalidWALFile = errors.New(\"installed WAL file is not a valid SQLite WAL file\")\n)\n\ntype installPhase int\n\nconst (\n\tinstallPhaseDB installPhase = iota\n\tinstallPhaseWAL\n\tinstallPhaseDone\n)\n\n// FullSink streams snapshot bytes into files described by a FullSnapshot header.\ntype FullSink struct {\n\tdir    string\n\theader *proto.FullSnapshot\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/rqlite/rqlite/blob/7586a4d1bdbd9a5a80021664c5a863cd850adb60/snapshot/sink_full.go#L15-L51","documentation":"ErrInvalidSQLiteFile is returned by FullSink.Close when, after the install completes, db.IsValidSQLiteFile determines the installed DB file does not bear a valid SQLite file header. It is a final integrity check preventing a corrupt file from becoming the node's database.","triggerScenarios":"The streamed DB bytes were corrupted or reordered in transit; the snapshot producer wrote a non-SQLite file; data was truncated then padded so byte counts matched but content is wrong.","commonSituations":"Custom snapshot transport with bit-flips or misordered chunks; restoring a snapshot from a source that was itself corrupt; disk corruption on the receiving node.","solutions":["Delete the installed file, obtain a fresh snapshot from the leader, and retry the install.","Verify checksums of the snapshot data end-to-end if using a custom transport.","Check the producing node's DB integrity (PRAGMA integrity_check) before re-snapshotting.","Investigate disk health on the receiving node if corruption recurs."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Optionally sanity-check the source DB before streaming it\nif !db.IsValidSQLiteFile(srcDBPath) {\n    return fmt.Errorf(\"refusing to snapshot: source is not a valid SQLite file\")\n}","typeGuard":null,"tryCatchPattern":"if err := sink.Close(); err != nil {\n    if errors.Is(err, snapshot.ErrInvalidSQLiteFile) {\n        // remove bad install, fetch fresh snapshot from leader\n        os.Remove(installPath)\n        return refetchSnapshot()\n    }\n    return err\n}","preventionTips":["Add end-to-end checksums to custom snapshot transports.","Run PRAGMA integrity_check on source nodes periodically.","Monitor node disks for corruption; use redundant snapshot sources.","Never hand-edit or post-process snapshot files before install."],"tags":["snapshot","data-integrity","sqlite"],"backgroundTag":"corrupt-sqlite-file","analyzedSha":"7586a4d1bdbd9a5a80021664c5a863cd850adb60","analyzedAt":"2026-09-03T07:03:02.260Z","contentChangedAt":"2026-09-03T07:03:02.260Z","schemaVersion":2},"datasetVersion":"2026-09-10T12:17:11.382Z"}