benbjohnson/litestream · error
fetch updated page %d: %w
Error message
fetch updated page %d: %w
What it means
Hydrator.ApplyUpdates fetches a changed page from the replica storage via FetchPage and wraps any failure as "fetch updated page %d". During incremental hydration, the page index reports which pages changed; each must be downloaded from the replica client. A storage/network failure fetching any page aborts the whole update application.
Source
Thrown at vfs.go:904
// Update the first page to pretend like we are in journal mode
if off == 0 && len(p) >= 28 {
p[18], p[19] = 0x01, 0x01
_, _ = rand.Read(p[24:28])
}
return n, nil
}
// ApplyUpdates fetches updated pages and writes them to the hydration file.
func (h *Hydrator) ApplyUpdates(ctx context.Context, updates map[uint32]ltx.PageIndexElem) error {
h.mu.Lock()
defer h.mu.Unlock()
for pgno, elem := range updates {
_, data, err := FetchPage(ctx, h.client, elem.Level, elem.MinTXID, elem.MaxTXID, elem.Offset, elem.Size)
if err != nil {
return fmt.Errorf("fetch updated page %d: %w", pgno, err)
}
off := int64(pgno-1) * int64(h.pageSize)
if _, err := h.file.WriteAt(data, off); err != nil {
return fmt.Errorf("write updated page %d: %w", pgno, err)
}
}
return nil
}
// WritePage writes a single page to the hydration file.
func (h *Hydrator) WritePage(pgno uint32, data []byte) error {
h.mu.Lock()
defer h.mu.Unlock()
off := int64(pgno-1) * int64(h.pageSize)
if _, err := h.file.WriteAt(data, off); err != nil {View on GitHub (pinned to 4ed7a308f6)
Solutions
- Read the wrapped cause: network/DNS errors indicate connectivity; 404/NoSuchKey indicates the LTX file was removed by retention — lengthen retention or disable it if a lifecycle policy is in place
- Verify replica credentials and endpoint configuration
- Retry the operation — ApplyUpdates can be re-run and will re-fetch the failed page
- Use litestream reset for the database to rebuild hydration state from scratch if the page index is stale
Defensive patterns
Strategy: retry
Validate before calling
// verify replica reachability before long operations
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if _, err := client.Head(ctx, replicaURL); err != nil {
// storage unreachable — fix credentials/endpoint first
} Try / catch
err := hydrator.ApplyUpdates(ctx, updates)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) || isRetryableStorageErr(err) {
// backoff and retry; ApplyUpdates is idempotent
}
} Prevention
- Set retention long enough that LTX files outlive any hydration catch-up window
- Rotate storage credentials before expiry and validate with a smoke test
- Configure network retries/backoff in the replica client and monitor connectivity
- Pin replica endpoint/bucket config and validate it with litestream replicas
When it happens
Trigger: Calling ApplyUpdates when the replica storage is unreachable (network outage, wrong bucket/endpoint credentials); the referenced LTX file at elem.Level/elem.MinTXID/elem.MaxTXID was deleted by retention before the fetch; context canceled mid-fetch.
Common situations: S3/GCS/Azure credentials rotated or expired; retention policy removed LTX files the local page index still references; transient network partition during long-running replication; misconfigured endpoint in replica config.
Related errors
- close iterator: %w
- fetch ltx files: %w
- replica sync: %w
- fetch ltx files: %w
- cannot determine L%d max ltx file for %q: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/28248d89d27a3478.
Report an issue: GitHub.