benbjohnson/litestream · error
cannot read last synced wal page: %w
Error message
cannot read last synced wal page: %w
What it means
lastPageMatch reads the WAL frame at the previously synced offset via readWALFileAt to compare it against LTX content. A short read, missing WAL, or IO error is wrapped as this error and causes verify to abort the incremental path.
Source
Thrown at db.go:1832
}
return info, nil
}
info.snapshotting = false
return info, nil
}
// lastPageMatch checks if the last page read in the WAL exists in the last LTX file.
func (db *DB) lastPageMatch(ctx context.Context, dec *ltx.Decoder, prevWALOffset, frameSize int64) (bool, error) {
if prevWALOffset <= WALHeaderSize {
return false, nil
}
frame, err := readWALFileAt(db.WALPath(), prevWALOffset, frameSize)
if err != nil {
return false, fmt.Errorf("cannot read last synced wal page: %w", err)
}
pgno := binary.BigEndian.Uint32(frame[0:])
fsalt1 := binary.BigEndian.Uint32(frame[8:])
fsalt2 := binary.BigEndian.Uint32(frame[12:])
data := frame[WALFrameHeaderSize:]
if fsalt1 != dec.Header().WALSalt1 || fsalt2 != dec.Header().WALSalt2 {
return false, nil
}
// Verify that the last page in the WAL exists in the last LTX file.
buf := make([]byte, dec.Header().PageSize)
for {
var hdr ltx.PageHeader
if err := dec.DecodePage(&hdr, buf); errors.Is(err, io.EOF) {
return false, nil // page not found in LTX file
} else if err != nil {
return false, fmt.Errorf("decode ltx page: %w", err)View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check WAL file size vs prevWALOffset (`ls -l db-wal`); a truncated WAL indicates a checkpoint raced the sync
- Verify no external processes touch the WAL file
- Fix filesystem/IO issues surfaced in the wrapped error
- `litestream reset` if local state is persistently inconsistent with the WAL
Defensive patterns
Strategy: retry
Validate before calling
fi, err := os.Stat(dbPath + "-wal")
if err == nil && fi.Size() < prevWALOffset { /* WAL truncated under expected offset */ } Try / catch
if err := db.Sync(ctx); err != nil {
if strings.Contains(err.Error(), "cannot read last synced wal page") {
// checkpoint raced sync: backoff-retry; persistent: reset state
}
} Prevention
- Accept that checkpoints truncate the WAL; let litestream resnapshot when detected
- Monitor WAL size vs sync lag
- Avoid external WAL truncation tools
When it happens
Trigger: readWALFileAt(db.WALPath(), prevWALOffset, frameSize) fails — WAL truncated below prevWALOffset, WAL deleted, or read/IO error at that offset.
Common situations: Checkpoint truncated the WAL between syncs while state said syncedToWALEnd was false; external process manipulating the WAL; disk errors.
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
- cannot read wal header: %w
- prev WAL offset is less than the header size: %d
- new wal reader with offset: %w
- offset (%d) must be greater than the wal header size (%d)
- unaligned wal offset %d for page size %d
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/50f8fc43e8674e6a.
Report an issue: GitHub.