benbjohnson/litestream · error

read ltx page frame: %w

Error message

read ltx page frame: %w

What it means

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.

Source

Thrown at replica_client.go:164

	// Otherwise read the file from the start of the page index.
	f, err = client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, info.Size-ltx.TrailerSize-8-int64(size), 0)
	if err != nil {
		return nil, fmt.Errorf("open ltx file: %w", err)
	}
	return f, nil
}

// FetchPage fetches and decodes a single page frame from an LTX file.
func FetchPage(ctx context.Context, client ReplicaClient, level int, minTXID, maxTXID ltx.TXID, offset, size int64) (ltx.PageHeader, []byte, error) {
	f, err := client.OpenLTXFile(ctx, level, minTXID, maxTXID, offset, size)
	if err != nil {
		return ltx.PageHeader{}, nil, fmt.Errorf("open ltx file: %w", err)
	}
	defer f.Close()

	b, err := io.ReadAll(f)
	if err != nil {
		return ltx.PageHeader{}, nil, fmt.Errorf("read ltx page frame: %w", err)
	}
	return ltx.DecodePageData(b)
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Retry the FetchPage call; per-page reads are cheap and idempotent (inspect the wrapped %w error).
  2. Add backoff/jitter and limit concurrency when fetching many pages in parallel.
  3. Increase timeouts on the HTTP/storage client used by the replica backend.
  4. Check provider status/quota if throttling errors recur.

Example fix

// before: no retry in page loop
hdr, data, err := litestream.FetchPage(ctx, client, level, minTXID, maxTXID, off, sz)
if err != nil { return err }
// after: retry transient read failures per page
hdr, data, err := litestream.FetchPage(ctx, client, level, minTXID, maxTXID, off, sz)
if err != nil && isTransient(err) { hdr, data, err = litestream.FetchPage(ctx, client, level, minTXID, maxTXID, off, sz) }
Defensive patterns

Strategy: retry

Validate before calling

if size <= 0 { return fmt.Errorf("invalid page frame size %d", size) } // validate before read

Try / catch

hdr, data, err := litestream.FetchPage(ctx, client, level, minTXID, maxTXID, offset, size)
if err != nil && isTransient(err) {
    hdr, data, err = litestream.FetchPage(ctx, client, level, minTXID, maxTXID, offset, size)
}
if err != nil { return fmt.Errorf("fetch page @%d: %w", offset, err) }

Prevention

When it happens

Trigger: 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.

Common situations: Large restores over unstable networks; S3/GCS throttling (SlowDown) during parallel page fetches; proxies terminating long-lived range reads.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/1e80a970b0126e9f. Report an issue: GitHub.