benbjohnson/litestream · error
list ltx files for catch-up: %w
Error message
list ltx files for catch-up: %w
What it means
Hydrator.CatchUp lists LTX files from the replica starting at fromTXID+1 (level 0) to apply everything up to toTXID. This error wraps a failure of client.LTXFiles — the listing request itself failed before any files could be applied.
Source
Thrown at vfs.go:817
defer h.mu.Unlock()
dec := ltx.NewDecoder(pr)
if err := dec.DecodeDatabaseTo(h.file); err != nil {
return fmt.Errorf("decode database: %w", err)
}
h.txid = infos[len(infos)-1].MaxTXID
return nil
}
// 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()
}
View on GitHub (pinned to 4ed7a308f6)
Solutions
- Unwrap the error for the backend cause; fix credentials, endpoint, or network and retry.
- Implement retry with backoff for transient listing failures (throttling/timeout).
- Verify the replica client config (bucket, prefix, region) matches where litestream is actually writing.
- If listing consistently fails, fall back to a full Restore once connectivity is restored, since CatchUp cannot proceed without the listing.
Example fix
// before
itr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)
if err != nil { return err }
// after
itr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)
if err != nil {
if isTransient(err) { return retryWithBackoff(...) }
return fmt.Errorf("list ltx files for catch-up: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// probe the replica before catch-up
if _, err := client.LTXFiles(ctx, 0, 1, false); err != nil {
return fmt.Errorf("replica unreachable: %w", err)
} Try / catch
itr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)
if err != nil {
if isRetryable(err) { return backoffRetry(ctx) }
return fmt.Errorf("list ltx files for catch-up: %w", err)
} Prevention
- Wrap storage listing calls in retry with exponential backoff
- Refresh cloud credentials before long-running catch-up loops
- Alert on replica listing failures — catch-up cannot degrade gracefully past this point
When it happens
Trigger: Calling CatchUp when the replica backend is unreachable, credentials are invalid, the bucket/container doesn't exist, or a transient network/API error (throttling, 5xx) occurs during the listing call.
Common situations: S3/GCS/Azure rate limiting during heavy sync; expired cloud credentials; DNS or VPN outage on the host; misconfigured replica path after moving the database.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- replica sync: %w
- fetch ltx files: %w
- cannot determine L%d max ltx file for %q: %w
- write ltx file: %w
- list level %d ltx files: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/e6790d73d77b7cdc.
Report an issue: GitHub.