benbjohnson/litestream · error
page map: %w
Error message
page map: %w
What it means
WALReader.pageMap failed while building the map of changed page numbers and latest frame contents, bounded by maxSyncWALBytes. This scan is the core of staging a sync; a read or parse error mid-scan aborts the whole sync for this iteration.
Source
Thrown at db.go:2082
}
} else if err != nil {
return result, fmt.Errorf("new wal reader with offset: %w", err)
}
}
// Build a mapping of changed page numbers and their latest content.
db.setSyncDiagPhase(diagPhaseSyncPageMap,
func(s *diagState) {
s.txID = txID
s.snapshotting = info.snapshotting
s.reason = info.reason
})
if info.snapshotting {
maxSyncWALBytes = 0
}
pageMap, maxOffset, walCommit, limited, err := rd.pageMap(ctx, maxSyncWALBytes)
if err != nil {
return result, fmt.Errorf("page map: %w", err)
}
result.limited = limited
if walCommit > 0 {
commit = walCommit
}
var sz int64
if maxOffset > 0 {
sz = maxOffset - info.offset
}
assert(sz >= 0, fmt.Sprintf("wal size must be positive: sz=%d, maxOffset=%d, info.offset=%d", sz, maxOffset, info.offset))
db.setSyncDiagPhase(diagPhaseSyncPrepareLTX,
func(s *diagState) {
s.txID = txID
s.walSize = sz
s.snapshotting = info.snapshotting
s.reason = info.reason
})
View on GitHub (pinned to 4ed7a308f6)
Solutions
- Retry — transient races with live checkpointing typically succeed on the next sync
- Force a checkpoint via the application (PRAGMA wal_checkpoint(TRUNCATE)) and restart Litestream for a clean snapshot
- Check for WAL corruption; restore from backup if frames are physically damaged
- Verify disk health and sufficient I/O headroom for large WALs
Defensive patterns
Strategy: retry
Validate before calling
// ensure WAL is at least header-sized and stable before sync st, err := os.Stat(dbPath + "-wal") ready := err == nil && st.Size() >= 32
Try / catch
if err := db.SyncAndWait(ctx); err != nil && strings.Contains(err.Error(), "page map") {
if !errors.Is(err, context.Canceled) {
backoffRetry(err)
}
} Prevention
- Configure retention/compaction so WALs don't grow unbounded between syncs
- Sync frequently (short sync intervals) to keep per-sync WAL scans small
- Monitor ctx cancellations vs real I/O errors separately
- Watch for disk hardware errors in dmesg when this repeats
When it happens
Trigger: rd.pageMap(ctx, maxSyncWALBytes) errors: I/O read failure mid-WAL, a frame whose checksum/validation fails, context cancellation, or a commit frame inconsistent with earlier frames.
Common situations: WAL being rewritten concurrently by SQLite during the scan; corrupted WAL frames after a crash; disk errors; huge WALs hitting I/O timeouts under memory pressure.
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
- set synchronous: %w
- checkpoint: %w
- checkpoint failed: %w
- sync database %s: %w
- enable wal failed, mode=%q
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/f561b1963924176c.
Report an issue: GitHub.