{"record":{"id":"5873c508df7e225c","repo":"benbjohnson/litestream","slug":"decode-header-w-5873c5","errorCode":null,"errorMessage":"decode header: %w","messagePattern":"decode header: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":852,"sourceCode":"\t}\n\n\treturn nil\n}\n\n// ApplyLTX fetches an entire LTX file and applies its pages to the hydration file.\nfunc (h *Hydrator) ApplyLTX(ctx context.Context, info *ltx.FileInfo) error {\n\th.logger.Debug(\"applying ltx to hydration file\", \"level\", info.Level, \"min\", info.MinTXID, \"max\", info.MaxTXID)\n\n\t// Fetch entire LTX file\n\trc, err := h.client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, 0, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open ltx file: %w\", err)\n\t}\n\tdefer rc.Close()\n\n\tdec := ltx.NewDecoder(rc)\n\tif err := dec.DecodeHeader(); err != nil {\n\t\treturn fmt.Errorf(\"decode header: %w\", err)\n\t}\n\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\n\t// Apply each page to the hydration file\n\tfor {\n\t\tvar phdr ltx.PageHeader\n\t\tdata := make([]byte, h.pageSize)\n\t\tif err := dec.DecodePage(&phdr, data); err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\treturn fmt.Errorf(\"decode page: %w\", err)\n\t\t}\n\n\t\toff := int64(phdr.Pgno-1) * int64(h.pageSize)\n\t\tif _, err := h.file.WriteAt(data, off); err != nil {\n\t\t\treturn fmt.Errorf(\"write page %d: %w\", phdr.Pgno, err)","sourceCodeStart":834,"sourceCodeEnd":870,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L834-L870","documentation":"ApplyLTX wraps the opened LTX reader in an ltx.Decoder and calls DecodeHeader. This error wraps a header decode failure, meaning the stream's first bytes are not a valid LTX header or could not be fully read — the file is corrupt, truncated, or not an LTX file at all.","triggerScenarios":"Calling ApplyLTX when the object downloaded from the replica is truncated (interrupted upload/download), zero bytes, encrypted/at-rest mismatch, or was overwritten by non-LTX content (e.g. wrong path written by another tool).","commonSituations":"Partial multipart uploads left in the bucket; a proxy/firewall returning an HTML error page stored as the object; version skew where the file was written with a newer incompatible LTX magic/version.","solutions":["Re-download the file and check its size and first bytes against the LTX magic; a 0-byte or HTML payload points at the storage/CDN layer, not litestream.","Compare the object's checksum with the replica listing; replace the corrupt object by re-snapshotting the database.","Check for LTX format version skew between writer and reader; upgrade litestream if headers use a newer version.","Skip the corrupt file and perform a full Restore from the latest valid snapshot."],"exampleFix":"// before\ndec := ltx.NewDecoder(rc)\nif err := dec.DecodeHeader(); err != nil { return err }\n// after\ndec := ltx.NewDecoder(rc)\nif err := dec.DecodeHeader(); err != nil {\n    if n, _ := rc.Seek(0, io.SeekEnd); n < ltx.HeaderSize {\n        return fmt.Errorf(\"ltx file truncated (%d bytes): %w\", n, err)\n    }\n    return fmt.Errorf(\"decode header: %w\", err)\n}","handlingStrategy":"validation","validationCode":"hdr, err := dec.DecodeHeader()\nif err != nil || hdr.Magic != ltx.Magic {\n    return fmt.Errorf(\"object is not a valid ltx file\")\n}","typeGuard":null,"tryCatchPattern":"if err := dec.DecodeHeader(); err != nil {\n    // verify object size; < HeaderSize means truncated upload\n    return fmt.Errorf(\"corrupt/truncated ltx header: %w\", err)\n}","preventionTips":["Verify object Content-Length matches expected size before decoding","Avoid proxies/CDNs that may substitute HTML error bodies for objects","Pin litestream versions so writer and reader LTX formats match"],"tags":["ltx","decode","corruption"],"backgroundTag":"invalid-json-response","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}