benbjohnson/litestream · error

cannot validate saved TXID for crash recovery: %w

Error message

cannot validate saved TXID for crash recovery: %w

What it means

During follow-mode crash recovery, opening the snapshot iterator to validate the saved TXID is still reachable failed. The replica's LTXFiles listing errored — backend connectivity, auth, or listing problem.

Source

Thrown at replica.go:638

	}

	// In follow mode, if the database already exists, attempt crash recovery
	// by reading the last applied TXID from the sidecar file.
	if opt.Follow {
		if _, statErr := os.Stat(opt.OutputPath); statErr == nil {
			txid, readErr := ReadTXIDFile(opt.OutputPath)
			if readErr != nil {
				return fmt.Errorf("read txid file for crash recovery: %w", readErr)
			}
			if txid == 0 {
				return fmt.Errorf("cannot resume follow mode: database exists but no -txid file found; delete the database to re-restore: %s", opt.OutputPath)
			}
			// Validate saved TXID is still reachable. If the earliest snapshot
			// starts after our saved TXID, retention has pruned the history
			// and we can't catch up incrementally.
			snapshotItr, itrErr := r.Client.LTXFiles(ctx, SnapshotLevel, 0, false)
			if itrErr != nil {
				return fmt.Errorf("cannot validate saved TXID for crash recovery: %w", itrErr)
			}

			var latestSnapshot *ltx.FileInfo
			for snapshotItr.Next() {
				latestSnapshot = snapshotItr.Item()
			}
			if err := snapshotItr.Err(); err != nil {
				_ = snapshotItr.Close()
				return fmt.Errorf("iterate snapshots for crash recovery validation: %w", err)
			}
			_ = snapshotItr.Close()

			if latestSnapshot != nil {
				if latestSnapshot.MinTXID > txid {
					return fmt.Errorf("cannot resume follow mode: saved TXID %s is behind the earliest snapshot (min TXID %s); replica history has been pruned -- delete %s and %s-txid to re-restore", txid, latestSnapshot.MinTXID, opt.OutputPath, opt.OutputPath)
				}
				if txid > latestSnapshot.MaxTXID {
					return fmt.Errorf("cannot resume follow mode: saved TXID %s is ahead of latest snapshot (max TXID %s); delete %s and %s-txid to re-restore", txid, latestSnapshot.MaxTXID, opt.OutputPath, opt.OutputPath)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check replica backend connectivity and credentials
  2. Retry starting litestream; the validation re-runs on startup
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at replica.go:638 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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