benbjohnson/litestream · error

detect full checkpoint: %w

Error message

detect full checkpoint: %w

What it means

When WAL header salts differ from the LTX-recorded salts, verify calls detectFullCheckpoint() to decide whether a full/restart checkpoint rewrote the WAL or whether syncing can continue incrementally. Any error from that detection is wrapped here and aborts the sync cycle.

Source

Thrown at db.go:1809

	} else if !lastPageMatch {
		info.reason = "last page does not exist in last ltx file, wal overwritten by another process"
		return info, nil
	}

	db.Logger.Debug("verify.2", "lastPageMatch", lastPageMatch)

	// Salt has changed which could indicate a FULL checkpoint.
	// If we have a last page match, then we can assume that the WAL has not been overwritten.
	if !saltMatch {
		db.Logger.Log(ctx, internal.LevelTrace, "wal restarted",
			"salt1", salt1,
			"salt2", salt2)

		info.offset = WALHeaderSize
		info.salt1, info.salt2 = salt1, salt2

		if detected, err := db.detectFullCheckpoint(ctx, [][2]uint32{{salt1, salt2}, {dec.Header().WALSalt1, dec.Header().WALSalt2}}); err != nil {
			return info, fmt.Errorf("detect full checkpoint: %w", err)
		} else if detected {
			info.reason = "full or restart checkpoint detected, snapshotting"
		} else {
			info.snapshotting = false
		}

		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

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Look at the wrapped inner error to distinguish WAL read vs LTX decode problems
  2. If LTX files are corrupt, `litestream reset` and resnapshot
  3. Reduce conflicting writers; ensure single-process ownership of the DB
  4. Retry after fixing transient IO conditions
Defensive patterns

Strategy: retry

Try / catch

if err := db.Sync(ctx); err != nil {
    if strings.Contains(err.Error(), "detect full checkpoint") {
        // transient IO: backoff and retry; corruption: reset
    }
}

Prevention

When it happens

Trigger: Salt mismatch path taken in verifyWithExecutor and detectFullCheckpoint fails — it reads WAL/LTX data to compare page content, so any WAL read or LTX decode error propagates here.

Common situations: Aggressive checkpointing by the application combined with IO errors; corrupted LTX files preventing content comparison; concurrent access to the database by another process.

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