{"record":{"id":"1b002c90a61f73dc","repo":"benbjohnson/litestream","slug":"reopen-ltx-file-at-offset-d-w","errorCode":null,"errorMessage":"reopen ltx file at offset %d: %w","messagePattern":"reopen ltx file at offset (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/resumable_reader.go","lineNumber":86,"sourceCode":"\n// resumableReaderBackoff is the base delay between retry attempts, doubling\n// per attempt. Zero-delay retries land every attempt inside the same provider\n// throttle window (e.g. Tigris 408 load shedding), guaranteeing exhaustion.\nconst resumableReaderBackoff = 250 * time.Millisecond\n\nfunc (r *ResumableReader) Read(p []byte) (int, error) {\n\tif r.err != nil {\n\t\treturn 0, r.err\n\t}\n\n\tfor {\n\t\t// Reopen the stream from the current offset if the previous\n\t\t// connection was closed (rc is nil after a retry).\n\t\tif r.rc == nil {\n\t\t\trc, err := r.client.OpenLTXFile(r.ctx, r.level, r.minTXID, r.maxTXID, r.offset, 0)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, os.ErrNotExist) || errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) || r.ctx.Err() != nil {\n\t\t\t\t\treturn 0, fmt.Errorf(\"reopen ltx file at offset %d: %w\", r.offset, err)\n\t\t\t\t}\n\t\t\t\tif retryErr := r.retry(fmt.Errorf(\"reopen ltx file at offset %d: %w\", r.offset, err)); retryErr != nil {\n\t\t\t\t\treturn 0, retryErr\n\t\t\t\t}\n\t\t\t\tr.logger.Debug(\"reopen ltx file failed, retrying\",\n\t\t\t\t\t\"level\", r.level, \"min\", r.minTXID, \"max\", r.maxTXID,\n\t\t\t\t\t\"offset\", r.offset, \"error\", err, \"attempt\", r.retryN)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tr.rc = rc\n\t\t}\n\n\t\tn, err := r.rc.Read(p)\n\t\tr.offset += int64(n)\n\n\t\tif err == nil {\n\t\t\treturn n, nil\n\t\t}","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/internal/resumable_reader.go#L68-L104","documentation":"ResumableReader.Read() tried to reopen the remote LTX file stream at the current offset after a connection drop and got a non-retryable error: os.ErrNotExist (file gone, e.g. compacted away), context.Canceled/DeadlineExceeded, or the reader's context already canceled. The read fails immediately instead of entering the retry/backoff path.","triggerScenarios":"Reading a streamed LTX file when the connection dropped, then on reopen OpenLTXFile returns NotExist because the LTX file was compacted/removed on the replica in the meantime, or the caller's context was canceled (shutdown, timeout, test cancellation).","commonSituations":"Long-running restore interrupted by litestream compaction removing the exact segment; restore canceled by the user (Ctrl-C) mid-stream; restore exceeding a deadline; TestResumableReader_ContextCancelAbortsBackoff exercising the cancel path.","solutions":["If ErrNotExist: restart the restore/replication from the latest available position — the original segment no longer exists","If context canceled/deadline: rerun with a longer deadline or without canceling; the error reflects the caller's own cancellation","Check replica retention settings — increase retention so segments aren't removed during active reads","Use `litestream ltx -level <level>` to see which LTX files actually exist on the replica","Verify only one litestream instance manages the replica (compaction by a second instance may race active reads)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"n, err := rr.Read(buf)\nif err != nil {\n    if errors.Is(err, os.ErrNotExist) {\n        // segment compacted away — restart from current replica position\n    } else if errors.Is(err, context.Canceled) {\n        // caller canceled — expected during shutdown\n    }\n    return err\n}","preventionTips":["Increase replica retention so segments outlive long reads","Avoid canceling restores mid-stream; use generous deadlines","Run a single litestream instance per replica to avoid compaction races"],"tags":["ltx","streaming","retry","context-cancel"],"backgroundTag":"resource-not-found","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"}