{"record":{"id":"60c06338ab64efb5","repo":"benbjohnson/litestream","slug":"new-ltx-compactor-w-60c063","errorCode":null,"errorMessage":"new ltx compactor: %w","messagePattern":"new ltx compactor: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":789,"sourceCode":"\n\tfor _, info := range infos {\n\t\th.logger.Debug(\"opening ltx file for hydration\", \"level\", info.Level, \"min\", info.MinTXID, \"max\", info.MaxTXID)\n\t\trc, err := h.client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, 0, 0)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"open ltx file: %w\", err)\n\t\t}\n\t\trdrs = append(rdrs, rc)\n\t}\n\n\tif len(rdrs) == 0 {\n\t\treturn fmt.Errorf(\"no ltx files for hydration\")\n\t}\n\n\t// Compact and decode using io.Pipe pattern\n\tpr, pw := io.Pipe()\n\tc, err := ltx.NewCompactor(pw, rdrs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"new ltx compactor: %w\", err)\n\t}\n\tc.HeaderFlags = ltx.HeaderFlagNoChecksum\n\th.compactor = c\n\n\tgo func() {\n\t\t_ = pw.CloseWithError(c.Compact(ctx))\n\t}()\n\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\n\tdec := ltx.NewDecoder(pr)\n\tif err := dec.DecodeDatabaseTo(h.file); err != nil {\n\t\treturn fmt.Errorf(\"decode database: %w\", err)\n\t}\n\n\th.txid = infos[len(infos)-1].MaxTXID\n\treturn nil","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L771-L807","documentation":"Hydrator.Restore constructs an ltx.NewCompactor over the opened readers; this error wraps a failure from that constructor. The LTX compactor validates its inputs (e.g. reader headers/ordering) before compacting, so a construction error means the reader set itself is invalid.","triggerScenarios":"Calling Restore with an empty reader slice (NewCompactor requires at least one reader), or LTX files whose headers cannot be validated as a coherent ordered chain during compactor setup.","commonSituations":"A bug or stale cache passing zero-length/empty LTX files; mixing LTX files from different databases with conflicting page sizes or timestamps; corrupted download from the object store truncated the header.","solutions":["Ensure at least one non-empty LTX reader is passed; check the infos list is non-empty before Restore.","Verify all LTX files belong to the same database (matching page size, database ID) — re-list from the correct replica path.","Re-download the offending file to rule out truncation/corruption; compare checksums with the replica listing.","Update litestream/ltx to matching versions if files were written by a newer writer with different header flags."],"exampleFix":"// before\nc, err := ltx.NewCompactor(pw, rdrs)\n// after\nif len(rdrs) == 0 { return fmt.Errorf(\"cannot compact: no ltx readers\") }\nc, err := ltx.NewCompactor(pw, rdrs)\nif err != nil { return fmt.Errorf(\"new ltx compactor: %w\", err) }","handlingStrategy":"validation","validationCode":"if len(rdrs) == 0 {\n    return fmt.Errorf(\"compactor requires at least one ltx reader\")\n}\nfor _, info := range infos {\n    if info.PageSize != expectedPageSize {\n        return fmt.Errorf(\"page size mismatch for ltx %d\", info.MaxTXID)\n    }\n}","typeGuard":null,"tryCatchPattern":"c, err := ltx.NewCompactor(pw, rdrs)\nif err != nil {\n    return fmt.Errorf(\"invalid ltx reader set: %w\", err)\n}","preventionTips":["Never pass empty reader slices to the compactor","Keep all LTX files from a single database/replica path","Match litestream versions between writer and reader to avoid header-flag skew"],"tags":["ltx","compaction","invalid-argument"],"backgroundTag":"invalid-argument","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"}