benbjohnson/litestream · error

_litestream_lock: %w

Error message

_litestream_lock: %w

What it means

Inside the passive-checkpoint barrier transaction, Litestream inserts into its internal _litestream_lock table to serialize against other sync activity. This error wraps the failure of that INSERT, aborting the passive checkpoint.

Source

Thrown at db.go:2504

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

		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,

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Restart Litestream so it re-creates its internal schema on the database
  2. Verify the table exists: `sqlite3 app.db '.tables' | grep _litestream_lock`
  3. Check for competing write locks or a read-only filesystem/mount
  4. Check disk space and database file permissions

Example fix

// before
sqlite3 app.db 'DROP TABLE _litestream_lock;'   # someone cleaned up tables
// after
systemctl restart litestream   # recreates internal tables
sqlite3 app.db '.tables' | grep _litestream_lock
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm litestream's internal schema exists
rows, _ := db.Query("SELECT count(*) FROM sqlite_master WHERE name='_litestream_lock'")
// count==0 => litestream has not initialized this database

Try / catch

// go
if err := checkpoint(ctx, CheckpointModePassive); err != nil {
    if strings.Contains(err.Error(), "_litestream_lock") {
        // schema missing or locked: restart litestream to re-init; check read-only fs
    }
}

Prevention

When it happens

Trigger: In checkpointWithExecutor (passive mode) when barrierTx.ExecContext(ctx, `INSERT INTO _litestream_lock (id) VALUES (1);`) fails — table missing (fresh/restored DB before Litestream initialized its schema), database locked, or disk I/O error.

Common situations: The _litestream_lock table was dropped or the DB was replaced/restored without Litestream re-initializing, a foreign process holds a write lock, or the filesystem is read-only/full.

Related errors


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