{"record":{"id":"70eb47f8bf63fe9a","repo":"benbjohnson/litestream","slug":"iterate-level-d-ltx-files-w","errorCode":null,"errorMessage":"iterate level %d ltx files: %w","messagePattern":"iterate level (.+?) ltx files: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica.go","lineNumber":1051,"sourceCode":"\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := r.applyLTXFile(ctx, f, info, pageSize); err != nil {\n\t\t\t\treturn closeLevel(fmt.Errorf(\n\t\t\t\t\t\"apply gap-fill ltx file (level=%d, min=%s, max=%s): %w\",\n\t\t\t\t\tinfo.Level, info.MinTXID, info.MaxTXID, err,\n\t\t\t\t))\n\t\t\t}\n\t\t\tcurrentTXID = info.MaxTXID\n\n\t\t\t// If we've bridged past the gap, we're done.\n\t\t\tif currentTXID+1 >= gapMinTXID {\n\t\t\t\treturn closeLevel(nil)\n\t\t\t}\n\t\t}\n\n\t\tif iterErr := itr.Err(); iterErr != nil {\n\t\t\treturn closeLevel(fmt.Errorf(\"iterate level %d ltx files: %w\", level, iterErr))\n\t\t}\n\t\tif _, err := closeLevel(nil); err != nil {\n\t\t\treturn currentTXID, err\n\t\t}\n\n\t\t// If we made progress at this level, restart from level 1.\n\t\tif currentTXID > afterTXID {\n\t\t\treturn currentTXID, nil\n\t\t}\n\t}\n\n\treturn currentTXID, nil\n}\n\n// RestoreV3 restores from a v0.3.x format backup.\nfunc (r *Replica) RestoreV3(ctx context.Context, opt RestoreOptions) error {\n\tclient, ok := r.Client.(ReplicaClientV3)\n\tif !ok {","sourceCodeStart":1033,"sourceCodeEnd":1069,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L1033-L1069","documentation":"After iterating a level's LTX files, fillFollowGap checks itr.Err() for any deferred iteration error (errors that surface during Next() rather than being returned immediately). If set, it is wrapped with the level number and returned; the iterator is still closed and any close error is joined.","triggerScenarios":"The storage iterator hit an error mid-iteration (e.g., a paginated S3 listing failed on a later page, an object metadata read failed), causing itr.Next() to return false and itr.Err() to be non-nil for levels 1 through SnapshotLevel-1.","commonSituations":"Long-lived follow sessions where a multi-page listing fails partway (token expired, 403 on later page, throttling), inconsistent storage backends with eventual-consistency listing gaps, custom client returning errors from Next without aborting.","solutions":["Check the wrapped itr.Err() cause for storage-side issues (403/429/timeouts) and address it","Verify IAM policy allows listing across all pages/prefixes of the replica path","Retry the sync; listing errors are typically transient","If using a custom ReplicaClient, ensure Next() propagates errors to Err() correctly"],"exampleFix":"// before: custom iterator swallowing errors mid-listing\nfunc (i *Iter) Next() bool { if !i.next() { return false }; return true } // error lost\n// after\nfunc (i *Iter) Next() bool {\n    if !i.next() { i.err = i.fetchErr(); return false }\n    return true\n}","handlingStrategy":"retry","validationCode":"// preflight full listing before relying on incremental follow\nitr, err := client.LTXFiles(ctx, 2, 0, false)\nif err != nil { return err }\nfor itr.Next() { _ = itr.Item() }\nif err := itr.Err(); err != nil { return fmt.Errorf(\"listing not fully traversable: %w\", err) }\nreturn itr.Close()","typeGuard":null,"tryCatchPattern":"if err := r.applyNewLTXFiles(ctx, f, pageSize); err != nil {\n    if strings.Contains(err.Error(), \"iterate level\") {\n        return retryWithBackoff(3, func() error { return r.applyNewLTXFiles(ctx, f, pageSize) })\n    }\n    return err\n}","preventionTips":["Ensure IAM allows listing all pages/prefixes of the replica path","Handle 429s with exponential backoff in client configurations","Implement custom iterators so Next() failures always surface via Err()","Keep follow sessions short or re-establish periodically to reset listing state"],"tags":["storage","s3","pagination","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"}