benbjohnson/litestream · error
rollback passive checkpoint barrier: %w
Error message
rollback passive checkpoint barrier: %w
What it means
During a passive checkpoint, Litestream first opened a short 'barrier' transaction, then rolls it back before bumping the litestream sequence number. This error wraps a failure of that rollback call, meaning the barrier transaction could not be cleanly rolled back (e.g. the connection or database is in a bad state). Because the transaction was supposed to be discarded anyway, the wrapped error usually reflects a deeper database/connection problem rather than lost data.
Source
Thrown at db.go:2534
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)
if err != nil {
return false, err
}
if barrierTx != nil {
if err = rollback(barrierTx); err != nil {
return false, fmt.Errorf("rollback passive checkpoint barrier: %w", err)
}
barrierTx = nil
}
if err = db.bumpLitestreamSeq(ctx); err != nil {
return false, fmt.Errorf("bump litestream seq: %w", err)
}
// If WAL hasn't been restarted, exit.
db.setSyncDiagPhase(diagPhaseCheckpointVerifyRestart,
func(s *diagState) {
s.checkpointMode = mode
s.lastSyncedWALOffset = exec.state.lastSyncedWALOffset
})
other, err := readWALHeader(db.WALPath())
if err != nil {
return false, err
} else if bytes.Equal(hdr, other) {View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check the wrapped inner error (%w) to find the real SQLite failure and fix that first (I/O, busy, closed handle).
- Ensure no concurrent db.Close() or another process is checkpointing/truncating the same WAL while Litestream runs.
- Retry the sync/checkpoint; a transient SQLITE_BUSY on rollback typically resolves on the next sync cycle.
- If the error persists, run 'litestream reset' or integrity_check the database; a corrupt WAL can break transaction teardown.
Defensive patterns
Strategy: retry
Validate before calling
if db == nil || db.SyncStatus() == litestream.SyncStatusError { /* recreate/reopen db handle before continuing */ } Try / catch
ok, err := dbCheckpoint(ctx, mode)
if err != nil && strings.Contains(err.Error(), "rollback passive checkpoint barrier") {
// inspect wrapped cause; log and let next sync retry
log.Printf("checkpoint barrier rollback failed, will retry: %v", err)
} Prevention
- Never close the *sql.DB while Litestream replication is active.
- Keep only one Litestream instance per database file.
- Monitor disk health and free space.
- Alert on repeated checkpoint failures rather than ignoring sync errors.
When it happens
Trigger: Running the internal passive-checkpoint path (db.checkpoint with CheckpointModePassive, e.g. during regular WAL sync) when rollback(barrierTx) fails: the underlying SQLite connection is busy/corrupt, the db handle was closed concurrently, or the driver returns an error rolling back an already-broken transaction.
Common situations: Database file closed or invalidated while a checkpoint is in flight (e.g. calling db.Close() concurrently); SQLite SQLITE_BUSY/IO errors on a slow or failing disk; using the library against a database whose WAL is being manipulated by another process.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- rollback post-checkpoint tx: %w
- begin passive checkpoint barrier: %w
- begin: %w
- begin transaction: %w
- commit transaction: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/d652249438bcb1c8.
Report an issue: GitHub.