{"record":{"id":"1e80a970b0126e9f","repo":"benbjohnson/litestream","slug":"read-ltx-page-frame-w","errorCode":null,"errorMessage":"read ltx page frame: %w","messagePattern":"read ltx page frame: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica_client.go","lineNumber":164,"sourceCode":"\t// Otherwise read the file from the start of the page index.\n\tf, err = client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, info.Size-ltx.TrailerSize-8-int64(size), 0)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"open ltx file: %w\", err)\n\t}\n\treturn f, nil\n}\n\n// FetchPage fetches and decodes a single page frame from an LTX file.\nfunc FetchPage(ctx context.Context, client ReplicaClient, level int, minTXID, maxTXID ltx.TXID, offset, size int64) (ltx.PageHeader, []byte, error) {\n\tf, err := client.OpenLTXFile(ctx, level, minTXID, maxTXID, offset, size)\n\tif err != nil {\n\t\treturn ltx.PageHeader{}, nil, fmt.Errorf(\"open ltx file: %w\", err)\n\t}\n\tdefer f.Close()\n\n\tb, err := io.ReadAll(f)\n\tif err != nil {\n\t\treturn ltx.PageHeader{}, nil, fmt.Errorf(\"read ltx page frame: %w\", err)\n\t}\n\treturn ltx.DecodePageData(b)\n}\n","sourceCodeStart":146,"sourceCodeEnd":168,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica_client.go#L146-L168","documentation":"FetchPage reads the requested page-frame bytes with io.ReadAll and wraps failures as \"read ltx page frame\". The object was opened but the body read failed, so the page frame is incomplete. The wrapped error carries the actual cause.","triggerScenarios":"Calling FetchPage when the read of the size-bounded page frame from the open LTX file fails — connection reset mid-range-read, storage backend I/O error, or throttling during partial restore.","commonSituations":"Large restores over unstable networks; S3/GCS throttling (SlowDown) during parallel page fetches; proxies terminating long-lived range reads.","solutions":["Retry the FetchPage call; per-page reads are cheap and idempotent (inspect the wrapped %w error).","Add backoff/jitter and limit concurrency when fetching many pages in parallel.","Increase timeouts on the HTTP/storage client used by the replica backend.","Check provider status/quota if throttling errors recur."],"exampleFix":"// before: no retry in page loop\nhdr, data, err := litestream.FetchPage(ctx, client, level, minTXID, maxTXID, off, sz)\nif err != nil { return err }\n// after: retry transient read failures per page\nhdr, data, err := litestream.FetchPage(ctx, client, level, minTXID, maxTXID, off, sz)\nif err != nil && isTransient(err) { hdr, data, err = litestream.FetchPage(ctx, client, level, minTXID, maxTXID, off, sz) }","handlingStrategy":"retry","validationCode":"if size <= 0 { return fmt.Errorf(\"invalid page frame size %d\", size) } // validate before read","typeGuard":null,"tryCatchPattern":"hdr, data, err := litestream.FetchPage(ctx, client, level, minTXID, maxTXID, offset, size)\nif err != nil && isTransient(err) {\n    hdr, data, err = litestream.FetchPage(ctx, client, level, minTXID, maxTXID, offset, size)\n}\nif err != nil { return fmt.Errorf(\"fetch page @%d: %w\", offset, err) }","preventionTips":["Retry per-page fetches; they are small, idempotent range reads.","Throttle parallel page fetches to avoid provider throttling.","Increase client read timeouts for large restores.","Log wrapped errors with offset to identify repeatedly failing frames."],"tags":["storage","ltx","io","network"],"backgroundTag":"file-read-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"}