benbjohnson/litestream · warning
rollback post-checkpoint tx: %w
Error message
rollback post-checkpoint tx: %w
What it means
After the boundary snapshot, Litestream releases the checkpoint's write transaction with rollback(tx) (the lock-table insert is intentionally discarded). This error wraps a failure of that rollback. Because the transaction is deliberately discarded, a rollback failure here is a hygiene problem, but leaving the write transaction open would block other writers, so it is reported.
Source
Thrown at db.go:2627
})
snapshotInfo := syncInfo{
offset: WALHeaderSize,
salt1: binary.BigEndian.Uint32(other[16:]),
salt2: binary.BigEndian.Uint32(other[20:]),
snapshotting: true,
reason: "checkpoint boundary snapshot",
}
result, err = db.sync(ctx, true, exec, snapshotInfo, 0)
if err != nil {
return false, fmt.Errorf("cannot snapshot after checkpoint: %w", err)
}
exec.applySyncResult(result)
// Release write lock before exiting.
// Use rollback() helper for consistency with releaseReadLock() and the
// defer above. See issue #934.
if err := rollback(tx); err != nil {
return false, fmt.Errorf("rollback post-checkpoint tx: %w", err)
}
exec.state.syncedSinceCheckpoint = false
return true, nil
}
// execCheckpoint issues a wal_checkpoint PRAGMA in the given mode and returns
// the number of frames in the WAL as reported by the checkpoint.
func (db *DB) execCheckpoint(ctx context.Context, mode string) (walFrameN int, err error) {
// Ignore if there is no underlying database.
if db.db == nil {
return 0, nil
}
// Track checkpoint metrics.
t := time.Now()
defer func() {
labels := prometheus.Labels{"mode": mode}View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check the wrapped error; if it is 'sql: transaction has already been committed or rolled back', the tx was already torn down and the write lock is free — safe to proceed.
- If a context cancellation caused it, avoid canceling the ctx passed to Litestream operations during checkpoints.
- Verify no concurrent db.Close() is running during replication.
- Retry; subsequent checkpoints will attempt teardown again.
Defensive patterns
Strategy: try-catch
Try / catch
if err != nil && strings.Contains(err.Error(), "rollback post-checkpoint tx") {
if strings.Contains(err.Error(), "already been committed or rolled back") {
// benign: lock already released, safe to continue
} else {
// investigate driver/connection state
}
} Prevention
- Don't cancel the replication context mid-checkpoint.
- Avoid concurrent Close() during checkpoint.
- Treat 'already rolled back' variants as benign.
- Keep drivers updated (modernc.org/sqlite).
When it happens
Trigger: rollback(tx) fails after a successful boundary snapshot: the transaction was already invalidated by a driver error, the connection was closed, or the context driving the transaction was canceled.
Common situations: Context cancellation mid-checkpoint (app shutdown, deadline) causing the driver to abort the tx; connection dropped due to database file issues; rare driver-level errors in modernc.org/sqlite.
Related errors
- rollback passive checkpoint barrier: %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/0bfa2ff62615e803.
Report an issue: GitHub.