{"record":{"id":"cda144367108edaa","repo":"rqlite/rqlite","slug":"unmarshaling-header-w","errorCode":null,"errorMessage":"unmarshaling header: %w","messagePattern":"unmarshaling header: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"snapshot/restore.go","lineNumber":39,"sourceCode":"\t// Read header length (4 bytes, big-endian).\n\tvar hdrLenBuf [HeaderSizeLen]byte\n\tn, err := io.ReadFull(r, hdrLenBuf[:])\n\ttotalRead += int64(n)\n\tif err != nil {\n\t\treturn totalRead, fmt.Errorf(\"reading header length: %w\", err)\n\t}\n\thdrLen := binary.BigEndian.Uint32(hdrLenBuf[:])\n\n\t// Read and parse header.\n\thdrBuf := make([]byte, hdrLen)\n\tn, err = io.ReadFull(r, hdrBuf)\n\ttotalRead += int64(n)\n\tif err != nil {\n\t\treturn totalRead, fmt.Errorf(\"reading header: %w\", err)\n\t}\n\thdr, err := UnmarshalSnapshotHeader(hdrBuf)\n\tif err != nil {\n\t\treturn totalRead, fmt.Errorf(\"unmarshaling header: %w\", err)\n\t}\n\n\t// The snapshot must be a full snapshot to extract a database.\n\tfull := hdr.GetFull()\n\tif full == nil {\n\t\treturn totalRead, fmt.Errorf(\"snapshot has no database\")\n\t}\n\n\t// Extract DB file. Wrap the source in a CRC32Reader so we can verify\n\t// the bytes match the header's CRC32 without a second pass over disk.\n\tdbFile, err := os.Create(dstPath)\n\tif err != nil {\n\t\treturn totalRead, err\n\t}\n\n\tdbCR := rsum.NewCRC32Reader(r)\n\tnr, err := io.CopyN(dbFile, dbCR, int64(full.DbHeader.SizeBytes))\n\ttotalRead += nr","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/rqlite/rqlite/blob/7586a4d1bdbd9a5a80021664c5a863cd850adb60/snapshot/restore.go#L21-L57","documentation":"Restore successfully read the header bytes but UnmarshalSnapshotHeader could not decode them into a valid snapshot header, and Restore wraps that failure as 'unmarshaling header'. This library throws it because the header bytes are corrupt or not in the expected protobuf format, so the snapshot layout cannot be interpreted.","triggerScenarios":"Calling snapshot.Restore with a stream whose header region contains garbage: corrupted file, wrong format (e.g. raw SQLite file instead of a rqlite snapshot stream), or bytes scrambled by an incompatible writer version.","commonSituations":"Attempting to restore a plain .db file (or a gzipped/compressed snapshot) directly through Restore without decompression/format conversion; bit rot on stored snapshots; passing output of a mismatched rqlite version.","solutions":["Confirm the input is an actual rqlite snapshot stream (produced by the snapshot writer), not a raw SQLite DB or a compressed artifact — decompress if ?compress was used.","Inspect the wrapped UnmarshalSnapshotHeader error for protobuf decode specifics.","Re-export a fresh snapshot from a healthy node and retry the restore.","Verify checksums/integrity of the stored snapshot file before restoring."],"exampleFix":"// before: feeding a raw sqlite file into Restore\nf, _ := os.Open(\"backup.db\")\nn, err := snapshot.Restore(f, dst)\n// after: only restore snapshot streams; handle compression\nvar r io.Reader = snapshotStream\nif compressed { r, _ = gzip.NewReader(snapshotStream) }\nn, err = snapshot.Restore(r, dst)","handlingStrategy":"validation","validationCode":"// ensure the input is a rqlite snapshot stream, decompressing if needed\nvar r io.Reader = raw\nif compressed { zr, err := gzip.NewReader(raw); if err != nil { return err }; r = zr }\nmagic, _ := peekBytes(r, 4)\nif isRawSQLiteFile(magic) { return fmt.Errorf(\"input is a raw DB, not a snapshot stream\") }","typeGuard":null,"tryCatchPattern":"n, err := snapshot.Restore(r, dst)\nif err != nil && strings.Contains(err.Error(), \"unmarshaling header\") {\n    return fmt.Errorf(\"source is not a valid rqlite snapshot; re-export it\")\n}","preventionTips":["Only feed Restore streams produced by the snapshot writer","Decompress compressed backups before restoring","Checksum stored snapshots and validate before use"],"tags":["protobuf","deserialization","snapshot","restore"],"backgroundTag":"corrupt-snapshot-header","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"}