benbjohnson/litestream · error

read ltx header: %w

Error message

read ltx header: %w

What it means

The page-size detection loop tried every candidate LTX file and each readPageSizeFromInfo call failed; the last underlying error is wrapped as 'read ltx header: %w'. If no files existed at all, a separate 'no ltx file available' error is returned.

Source

Thrown at vfs.go:2799

	}
	return pageSize, nil
}

func detectPageSizeFromInfos(ctx context.Context, client ReplicaClient, infos []*ltx.FileInfo) (uint32, error) {
	var lastErr error
	for i := len(infos) - 1; i >= 0; i-- {
		pageSize, err := readPageSizeFromInfo(ctx, client, infos[i])
		if err != nil {
			lastErr = err
			continue
		}
		if !isSupportedPageSize(pageSize) {
			return 0, fmt.Errorf("unsupported page size: %d", pageSize)
		}
		return pageSize, nil
	}
	if lastErr != nil {
		return 0, fmt.Errorf("read ltx header: %w", lastErr)
	}
	return 0, fmt.Errorf("no ltx file available to determine page size")
}

func readPageSizeFromInfo(ctx context.Context, client ReplicaClient, info *ltx.FileInfo) (uint32, error) {
	rc, err := client.OpenLTXFile(ctx, info.Level, info.MinTXID, info.MaxTXID, 0, ltx.HeaderSize)
	if err != nil {
		return 0, fmt.Errorf("open ltx file: %w", err)
	}
	defer rc.Close()
	dec := ltx.NewDecoder(rc)
	if err := dec.DecodeHeader(); err != nil {
		return 0, fmt.Errorf("decode ltx header: %w", err)
	}
	return dec.Header().PageSize, nil
}

func isSupportedPageSize(pageSize uint32) bool {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Read the wrapped error to identify why headers could not be read
  2. Verify replica storage contains at least one readable LTX file (litestream ltx -level all)
  3. Check credentials and network access to the storage endpoint
  4. Confirm proxies/gateways support the range reads used for header-only fetches
Defensive patterns

Strategy: retry

Validate before calling

// confirm at least one readable LTX file exists before opening VFS
infos, err := listAllLTXInfos(ctx, client)
if err != nil || len(infos) == 0 {
    return fmt.Errorf("replica has no readable ltx files")
}

Try / catch

if err := openVFS(); err != nil {
    if strings.Contains(err.Error(), "read ltx header") {
        // storage/network issue at open time
        time.Sleep(retryDelay); return openVFS()
    }
    return err
}

Prevention

When it happens

Trigger: All candidate LTX files unreadable during page-size discovery: storage unreachable, credentials failing, zero-byte/truncated headers, or OpenLTXFile errors on every file.

Common situations: Freshly restored/empty replica bucket; network outage at VFS open time; IAM policy changes revoking read access; proxy stripping request ranges used to read only ltx.HeaderSize bytes.

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/1edc34387462b06a. Report an issue: GitHub.