{"record":{"id":"e6790d73d77b7cdc","repo":"benbjohnson/litestream","slug":"list-ltx-files-for-catch-up-w","errorCode":null,"errorMessage":"list ltx files for catch-up: %w","messagePattern":"list ltx files for catch-up: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":817,"sourceCode":"\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\n}\n\n// 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","sourceCodeStart":799,"sourceCodeEnd":835,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L799-L835","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nitr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)\nif err != nil { return err }\n// after\nitr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)\nif err != nil {\n    if isTransient(err) { return retryWithBackoff(...) }\n    return fmt.Errorf(\"list ltx files for catch-up: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// probe the replica before catch-up\nif _, err := client.LTXFiles(ctx, 0, 1, false); err != nil {\n    return fmt.Errorf(\"replica unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"itr, err := h.client.LTXFiles(ctx, 0, fromTXID+1, false)\nif err != nil {\n    if isRetryable(err) { return backoffRetry(ctx) }\n    return fmt.Errorf(\"list ltx files for catch-up: %w\", err)\n}","preventionTips":["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"],"tags":["network","storage","replication"],"backgroundTag":"api-request-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"}