benbjohnson/litestream · error

cannot copy wal before checkpoint: %w

Error message

cannot copy wal before checkpoint: %w

What it means

Before a checkpoint, Litestream must copy (seal) all pending WAL frames into an LTX file via verifyAndSyncWithExecutor. This error wraps any failure in that pre-checkpoint sync, meaning the WAL could not be fully replicated before checkpointing, so the checkpoint is aborted to avoid data loss.

Source

Thrown at db.go:2487

	db.setSyncDiagPhase(diagPhaseCheckpointReadWALHeader,
		func(s *diagState) {
			s.checkpointMode = mode
			s.lastSyncedWALOffset = exec.state.lastSyncedWALOffset
		})
	hdr, err := readWALHeader(db.WALPath())
	if err != nil {
		return false, err
	}

	// Copy end of WAL before checkpoint to copy as much as possible.
	db.setSyncDiagPhase(diagPhaseCheckpointCopyBefore,
		func(s *diagState) {
			s.checkpointMode = mode
			s.lastSyncedWALOffset = exec.state.lastSyncedWALOffset
		})
	result, err := db.verifyAndSyncWithExecutor(ctx, true, exec, 0)
	if err != nil {
		return false, fmt.Errorf("cannot copy wal before checkpoint: %w", err)
	}
	exec.applySyncResult(result)

	var barrierTx *sql.Tx
	if mode == CheckpointModePassive {
		barrierTx, err = db.db.BeginTx(ctx, nil)
		if err != nil {
			return false, fmt.Errorf("begin passive checkpoint barrier: %w", err)
		}
		defer func() {
			if barrierTx != nil {
				_ = rollback(barrierTx)
			}
		}()

		if _, err := barrierTx.ExecContext(ctx, `INSERT INTO _litestream_lock (id) VALUES (1);`); err != nil {
			return false, fmt.Errorf("_litestream_lock: %w", err)
		}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check the wrapped inner error: if it's storage/auth related, fix credentials/network and verify with `litestream replicate` logs
  2. Free disk space if local LTX writes failed
  3. Run `litestream reset` only if local LTX state is corrupt (accepting re-upload)
  4. Retry once storage is healthy; the checkpoint will be reattempted on the next sync

Example fix

// before
# checkpoint fails: cannot copy wal before checkpoint: s3: ... AccessDenied
// after
# fix IAM policy so s3:PutObject is allowed, then
litestream ltx -db /var/lib/db/app.db
Defensive patterns

Strategy: retry

Validate before calling

// probe replica storage writability before triggering a checkpoint
if err := replicaClientProbe(ctx); err != nil { log.Printf("storage unavailable: %v", err) }

Try / catch

// go
if err := checkpoint(ctx, mode); err != nil {
    if strings.Contains(err.Error(), "cannot copy wal before checkpoint") {
        // inspect wrapped cause (S3 AccessDenied, ENOSPC...) and retry after fix
    }
}

Prevention

When it happens

Trigger: In checkpointWithExecutor when the initial db.verifyAndSyncWithExecutor(ctx, true, exec, 0) returns an error — replica client I/O failure, LTX write error, or WAL read error during the copy.

Common situations: Object storage unreachable (S3 creds/expired tokens, network outage), disk full, corrupt WAL preventing page encoding, or replica write permission problems.

Related errors


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