{"record":{"id":"23bdf106f4e8c672","repo":"benbjohnson/litestream","slug":"open-ltx-file-w-23bdf1","errorCode":null,"errorMessage":"open ltx file: %w","messagePattern":"open ltx file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":776,"sourceCode":"}\n\n// Restore restores the database from LTX files to the hydration file.\nfunc (h *Hydrator) Restore(ctx context.Context, infos []*ltx.FileInfo) error {\n\t// Open all LTX files as readers\n\trdrs := make([]io.Reader, 0, len(infos))\n\tdefer func() {\n\t\tfor _, rd := range rdrs {\n\t\t\tif closer, ok := rd.(io.Closer); ok {\n\t\t\t\t_ = closer.Close()\n\t\t\t}\n\t\t}\n\t}()\n\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() {","sourceCodeStart":758,"sourceCodeEnd":794,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L758-L794","documentation":"Hydrator.Restore builds the hydration file by opening each LTX file listed in `infos` from the replica client and compacting them together. This error wraps a failure from client.OpenLTXFile while opening one of those files. It is a thin wrapper: the underlying cause (from the storage backend) is embedded via %w and is the real diagnostic.","triggerScenarios":"Calling Hydrator.Restore(ctx, infos) where any info entry references an LTX file that OpenLTXFile cannot open on the replica — object deleted by retention/GC, wrong bucket/container credentials, network failure, or the FileInfo metadata being stale relative to what the replica actually holds.","commonSituations":"Replica retention removed a level-0 LTX file between the ListLTXFiles call and Restore; S3/GCS credentials rotated or revoked; restoring after `litestream reset` against a replica with mismatched TXIDs; offline development machine pointing at an unreachable object store.","solutions":["Unwrap the error (errors.Unwrap / %v print) to see the backend cause; fix storage credentials, network, or bucket config accordingly.","Re-list LTX files immediately before Restore so `infos` reflects what the replica currently holds; skip or re-fetch missing files.","If the replica state is corrupt or files were pruned, run `litestream reset` for the database and re-hydrate from the latest snapshot.","Verify retention settings so the files needed for restore are not deleted mid-restore; raise retention or disable lifecycle cleanup on the bucket."],"exampleFix":"// before\ninfos, _ := client.ListLTXFiles(ctx)\nerr := hydrator.Restore(ctx, infos)\n// after\ninfos, err := client.ListLTXFiles(ctx)\nif err != nil { return err }\ninfos = filterExisting(ctx, client, infos) // drop pruned files before opening\nerr = hydrator.Restore(ctx, infos)","handlingStrategy":"retry","validationCode":"// check file presence before restore\nfor _, info := range infos {\n    if _, err := client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, 0, 0); err != nil {\n        return fmt.Errorf(\"ltx %d-%d unavailable: %w\", info.MinTXID, info.MaxTXID, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := hydrator.Restore(ctx, infos); err != nil {\n    var nf *fs.PathError\n    if errors.As(err, &nf) { /* re-list and fall back to snapshot restore */ }\n}","preventionTips":["Re-list LTX files immediately before restore to avoid stale FileInfos","Set retention longer than the maximum expected restore time","Validate storage credentials at startup with a cheap HEAD/List call"],"tags":["storage","replication","file-open-failed"],"backgroundTag":"file-not-found","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"}