{"record":{"id":"6f485ba1336173ce","repo":"benbjohnson/litestream","slug":"read-ltx-page-index-w","errorCode":null,"errorMessage":"read ltx page index: %w","messagePattern":"read ltx page index: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica_client.go","lineNumber":132,"sourceCode":"// fetchPageIndexData fetches a chunk of the end of the file to get the page index.\n// If the fetch was smaller than the actual page index, another call is made to fetch the rest.\nfunc fetchPageIndexData(ctx context.Context, client ReplicaClient, info *ltx.FileInfo) (io.ReadCloser, error) {\n\t// Fetch the end of the file to get the page index.\n\toffset := info.Size - DefaultEstimatedPageIndexSize\n\tif offset < 0 {\n\t\toffset = 0\n\t}\n\n\tf, err := client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, offset, 0)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"open ltx file: %w\", err)\n\t}\n\tdefer f.Close()\n\n\t// If we have read the full size of the page index, return the page index block as a reader.\n\tb, err := io.ReadAll(f)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read ltx page index: %w\", err)\n\t}\n\t// The replica may return fewer bytes than a page index footer occupies, for\n\t// example if the file is truncated or otherwise corrupt. Slicing the footer\n\t// off the end unchecked would index past the start of the buffer and panic.\n\tif len(b) < ltx.TrailerSize+8 {\n\t\treturn nil, fmt.Errorf(\"ltx file too short to contain a page index: %d bytes\", len(b))\n\t}\n\n\tsize := binary.BigEndian.Uint64(b[len(b)-ltx.TrailerSize-8:])\n\tif off := len(b) - int(size) - ltx.TrailerSize - 8; off > 0 {\n\t\treturn io.NopCloser(bytes.NewReader(b[off:])), nil\n\t}\n\n\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}","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica_client.go#L114-L150","documentation":"Init reads the whole LTX file to locate the page index; io.ReadAll failures are wrapped as \"read ltx page index\". This means the object opened successfully but streaming its bytes failed mid-read. The wrapped error carries the actual transport/storage failure.","triggerScenarios":"Calling Init when client.OpenLTXFile succeeds but the subsequent read of the page index block fails — interrupted connection to the replica, aborted range read, or storage backend I/O error while reading the object body.","commonSituations":"Flaky network to S3/GCS/Azure during restore; proxy or load balancer cutting long reads; provider throttling mid-stream; oversized LTX files hitting read timeouts.","solutions":["Retry the operation; this is usually a transient stream failure (inspect the wrapped %w error).","Check for provider throttling (HTTP 503 SlowDown) and add backoff.","Increase client/proxy read timeouts for large LTX files.","Verify network stability between the host and the storage endpoint."],"exampleFix":"// before: single attempt\nb, err := litestream.Init(ctx, client, level, minTXID, maxTXID)\n// after: retry transient read failures\nvar r io.ReadCloser\nfor i := 0; i < 3; i++ {\n    r, err = litestream.Init(ctx, client, level, minTXID, maxTXID)\n    if err == nil || !isTransient(err) { break }\n    time.Sleep(time.Duration(1<<i) * time.Second)\n}","handlingStrategy":"retry","validationCode":"if err := pingReplica(ctx, client); err != nil { return fmt.Errorf(\"replica unreachable: %w\", err) }","typeGuard":null,"tryCatchPattern":"r, err := litestream.Init(ctx, client, level, minTXID, maxTXID)\nif err != nil {\n    if isTransientNetErr(err) { r, err = retryWithBackoff(3, func() (io.ReadCloser, error) { return litestream.Init(ctx, client, level, minTXID, maxTXID) }) }\n    if err != nil { return err }\n}","preventionTips":["Use retries with exponential backoff for object-store reads.","Set generous read timeouts for large LTX files.","Watch for provider throttling and cap request concurrency.","Keep hosts on stable network paths to the storage endpoint."],"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-14T00:17:10.932Z"}