benbjohnson/litestream · error
apply ltx to hydrated file: %w
Error message
apply ltx to hydrated file: %w
What it means
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.
Source
Thrown at vfs.go:828
// CatchUp applies updates from LTX files between fromTXID and toTXID.
func (h *Hydrator) CatchUp(ctx context.Context, fromTXID, toTXID ltx.TXID) error {
h.logger.Debug("catching up hydration", "from", fromTXID, "to", toTXID)
// Fetch LTX files from fromTXID+1 to toTXID
itr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)
if err != nil {
return fmt.Errorf("list ltx files for catch-up: %w", err)
}
defer itr.Close()
for itr.Next() {
info := itr.Item()
if info.MaxTXID > toTXID {
break
}
if err := h.ApplyLTX(ctx, info); err != nil {
return fmt.Errorf("apply ltx to hydrated file: %w", err)
}
h.mu.Lock()
h.txid = info.MaxTXID
h.mu.Unlock()
}
return nil
}
// ApplyLTX fetches an entire LTX file and applies its pages to the hydration file.
func (h *Hydrator) ApplyLTX(ctx context.Context, info *ltx.FileInfo) error {
h.logger.Debug("applying ltx to hydration file", "level", info.Level, "min", info.MinTXID, "max", info.MaxTXID)
// Fetch entire LTX file
rc, err := h.client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, 0, 0)
if err != nil {
return fmt.Errorf("open ltx file: %w", err)View on GitHub (pinned to 4ed7a308f6)
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).
Example fix
// before
if err := h.ApplyLTX(ctx, info); err != nil {
return fmt.Errorf("apply ltx to hydrated file: %w", err)
}
// after
if err := h.ApplyLTX(ctx, info); err != nil {
logger.Warn("catch-up failed; falling back to full restore", "txid", info.MaxTXID, "err", err)
return h.Restore(ctx, latestInfos)
} Defensive patterns
Strategy: fallback
Validate before calling
// confirm the file still exists on the replica before applying
itr, _ := client.LTXFiles(ctx, info.Level, info.MinTXID, false)
if !itr.Next() { return ErrLTXGone } Try / catch
if err := h.ApplyLTX(ctx, info); err != nil {
log.Warn("incremental catch-up failed, falling back to full restore", "err", err)
return h.Restore(ctx, latestInfos)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/1ccf8cc8023f8dbd.
Report an issue: GitHub.