{"record":{"id":"75ba7cb3c30c0041","repo":"benbjohnson/litestream","slug":"close-l1-iterator-w-75ba7c","errorCode":null,"errorMessage":"close l1 iterator: %w","messagePattern":"close l1 iterator: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":3041,"sourceCode":"\n\tdb.Logger.Debug(\"starting l0 retention enforcement\", \"retention\", db.L0Retention)\n\n\tdbName := filepath.Base(db.Path())\n\n\t// Determine the highest TXID that has been compacted into L1.\n\titr, err := db.Replica.Client.LTXFiles(ctx, 1, 0, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fetch l1 files: %w\", err)\n\t}\n\tvar maxL1TXID ltx.TXID\n\tfor itr.Next() {\n\t\tinfo := itr.Item()\n\t\tif info.MaxTXID > maxL1TXID {\n\t\t\tmaxL1TXID = info.MaxTXID\n\t\t}\n\t}\n\tif err := itr.Close(); err != nil {\n\t\treturn fmt.Errorf(\"close l1 iterator: %w\", err)\n\t}\n\tif maxL1TXID == 0 {\n\t\tinternal.L0RetentionGaugeVec.WithLabelValues(dbName, \"eligible\").Set(0)\n\t\tinternal.L0RetentionGaugeVec.WithLabelValues(dbName, \"not_compacted\").Set(0)\n\t\tinternal.L0RetentionGaugeVec.WithLabelValues(dbName, \"too_recent\").Set(0)\n\t\treturn nil\n\t}\n\n\tthreshold := time.Now().Add(-db.L0Retention)\n\titr, err = db.Replica.Client.LTXFiles(ctx, 0, 0, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fetch l0 files: %w\", err)\n\t}\n\tdefer itr.Close()\n\n\tvar (\n\t\tdeleted           []*ltx.FileInfo\n\t\tlastInfo          *ltx.FileInfo","sourceCodeStart":3023,"sourceCodeEnd":3059,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L3023-L3059","documentation":"Wraps an error from closing the L1 file iterator after determining maxL1TXID. Iterator Close flushes pending backend errors (e.g. failed pagination of a cloud listing), so a close error means the listing may have been incomplete and the computed max TXID cannot be trusted.","triggerScenarios":"L0 retention run where itr.Close() returns an error from the underlying remote listing, typically a failed S3/GS continuation-token page fetch that the iterator surfaces only on Close (db.go:3041).","commonSituations":"Large buckets whose listing spans many pages; transient 5xx or timeout on a later page; provider throttling during long listings.","solutions":["Retry the operation; a later successful Close confirms a complete listing.","Prune old files via retention so listings stay small.","Check provider throttling limits and request pacing for large buckets.","Confirm custom ReplicaClient implementations propagate page-fetch errors through Close."],"exampleFix":"// before\nif err := itr.Close(); err != nil { return fmt.Errorf(\"close l1 iterator: %w\", err) }\n// after (caller retry with backoff)\nif err := enforceL0Retention(ctx, db); err != nil && isTransient(err) {\n    time.Sleep(backoff)\n    err = enforceL0Retention(ctx, db)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := itr.Close(); err != nil {\n    if isTransient(err) { return retryWithBackoff(ctx) }\n    return fmt.Errorf(\"close l1 iterator: %w\", err)\n}","preventionTips":["Always treat iterator Close errors as listing failures, never ignore them.","Keep buckets pruned so listings span fewer pages.","Watch provider throttling metrics for large buckets."],"tags":["iterator","storage","listing","pagination"],"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-14T00:17:10.932Z"}