{"record":{"id":"1ccf8cc8023f8dbd","repo":"benbjohnson/litestream","slug":"apply-ltx-to-hydrated-file-w","errorCode":null,"errorMessage":"apply ltx to hydrated file: %w","messagePattern":"apply ltx to hydrated file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":828,"sourceCode":"// CatchUp applies updates from LTX files between fromTXID and toTXID.\nfunc (h *Hydrator) CatchUp(ctx context.Context, fromTXID, toTXID ltx.TXID) error {\n\th.logger.Debug(\"catching up hydration\", \"from\", fromTXID, \"to\", toTXID)\n\n\t// Fetch LTX files from fromTXID+1 to toTXID\n\titr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"list ltx files for catch-up: %w\", err)\n\t}\n\tdefer itr.Close()\n\n\tfor itr.Next() {\n\t\tinfo := itr.Item()\n\t\tif info.MaxTXID > toTXID {\n\t\t\tbreak\n\t\t}\n\n\t\tif err := h.ApplyLTX(ctx, info); err != nil {\n\t\t\treturn fmt.Errorf(\"apply ltx to hydrated file: %w\", err)\n\t\t}\n\n\t\th.mu.Lock()\n\t\th.txid = info.MaxTXID\n\t\th.mu.Unlock()\n\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)","sourceCodeStart":810,"sourceCodeEnd":846,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L810-L846","documentation":"During Hydrator.CatchUp, each listed LTX file is applied to the hydration file via ApplyLTX. This error wraps any failure returned by ApplyLTX — open, header decode, page decode, or page write — indicating catch-up stopped partway through the TXID range.","triggerScenarios":"Calling CatchUp where an intermediate LTX file fails to open (deleted from replica), fails to decode (corrupt/truncated download), or its pages cannot be written (disk full, hydration file closed), causing ApplyLTX to return an error.","commonSituations":"Retention deleting level-0 files faster than catch-up consumes them; corrupted object in the replica; disk pressure on the hydration volume; concurrent access closing the hydration file mid-apply.","solutions":["Unwrap to find the ApplyLTX cause (open vs decode vs write) and address it — most often re-fetching the file or freeing disk space.","Adjust retention so level-0 files outlive catch-up consumption, or increase catch-up frequency.","If a file is permanently missing from the replica, abandon incremental catch-up and re-run a full Restore from the latest snapshot.","Ensure no other goroutine closes or truncates the hydration file while CatchUp runs (h.file is shared)."],"exampleFix":"// before\nif err := h.ApplyLTX(ctx, info); err != nil {\n    return fmt.Errorf(\"apply ltx to hydrated file: %w\", err)\n}\n// after\nif err := h.ApplyLTX(ctx, info); err != nil {\n    logger.Warn(\"catch-up failed; falling back to full restore\", \"txid\", info.MaxTXID, \"err\", err)\n    return h.Restore(ctx, latestInfos)\n}","handlingStrategy":"fallback","validationCode":"// confirm the file still exists on the replica before applying\nitr, _ := client.LTXFiles(ctx, info.Level, info.MinTXID, false)\nif !itr.Next() { return ErrLTXGone }","typeGuard":null,"tryCatchPattern":"if err := h.ApplyLTX(ctx, info); err != nil {\n    log.Warn(\"incremental catch-up failed, falling back to full restore\", \"err\", err)\n    return h.Restore(ctx, latestInfos)\n}","preventionTips":["Set retention comfortably above catch-up lag","Run catch-up on a timer so gaps stay small","Always implement full-restore fallback for incremental apply failures"],"tags":["replication","ltx","apply"],"backgroundTag":"database-write-failed","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"}