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

  1. Check WAL file size vs prevWALOffset (`ls -l db-wal`); a truncated WAL indicates a checkpoint raced the sync
  2. Verify no external processes touch the WAL file
  3. Fix filesystem/IO issues surfaced in the wrapped error
  4. `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

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


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