benbjohnson/litestream · error

cannot seal wal before passive checkpoint: %w

Error message

cannot seal wal before passive checkpoint: %w

What it means

After acquiring the barrier lock in a passive checkpoint, Litestream performs one more sync to seal (fully replicate) the WAL before running the actual PRAGMA wal_checkpoint. This error wraps failure of that sealing sync, and the checkpoint is aborted to guarantee the replica has all WAL data first.

Source

Thrown at db.go:2509

	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)
		}

		result, err = db.verifyAndSyncWithExecutor(ctx, true, exec, 0)
		if err != nil {
			return false, fmt.Errorf("cannot seal wal before passive checkpoint: %w", err)
		}
		exec.applySyncResult(result)
	}

	frameSize := int64(db.pageSize + WALFrameHeaderSize)
	preCheckpointFrameN := 0
	if exec.state.lastSyncedWALOffset > WALHeaderSize {
		preCheckpointFrameN = int((exec.state.lastSyncedWALOffset - WALHeaderSize) / frameSize)
	}

	// Execute checkpoint and immediately issue a write to the WAL to ensure
	// a new page is written.
	db.setSyncDiagPhase(diagPhaseCheckpointExec,
		func(s *diagState) {
			s.checkpointMode = mode
			s.lastSyncedWALOffset = exec.state.lastSyncedWALOffset
		})
	walFrameN, err := db.execCheckpoint(ctx, mode)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Inspect the wrapped inner error and fix the underlying sync failure (storage creds, network, disk)
  2. Retry the checkpoint after storage is reachable
  3. Run `litestream reset` only if local LTX state is confirmed corrupt
  4. Monitor replica storage health; consider `auto-recover: true` cautiously per docs

Example fix

// before
litestream ltx ...   # cannot seal wal before passive checkpoint: context deadline exceeded
// after
# raise storage timeout / fix network, then retry
litestream ltx -db /var/lib/db/app.db
Defensive patterns

Strategy: retry

Validate before calling

// verify storage is reachable before running passive checkpoints
if err := storageHealthCheck(ctx); err != nil { log.Printf("skip checkpoint: %v", err) }

Try / catch

// go
if err := checkpoint(ctx, CheckpointModePassive); err != nil {
    if strings.Contains(err.Error(), "cannot seal wal before passive checkpoint") {
        // inspect wrapped sync error (network, creds, disk) and retry after remediation
    }
}

Prevention

When it happens

Trigger: In checkpointWithExecutor (passive mode) when db.verifyAndSyncWithExecutor(ctx, true, exec, 0) fails after the _litestream_lock insert — same causes as pre-checkpoint copy: storage failures, WAL read/encode errors, or client I/O errors.

Common situations: Object storage outages or expired credentials mid-checkpoint, disk full during LTX write, corrupt WAL page producing an encode error, or transient network failures.

Related errors


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