benbjohnson/litestream · error

create _litestream_seq table: %w

Error message

create _litestream_seq table: %w

What it means

Litestream wraps a failure to create the internal `_litestream_seq` bookkeeping table during DB initialization (db.init). This table forces a write into the WAL when the database is empty so that replication has a starting point. The error wraps the underlying SQLite driver error, so the real cause (disk full, permissions, corruption, connection failure) is in the wrapped message.

Source

Thrown at db.go:1086

			db.db.Close()
			db.f.Close()
			db.db, db.f = nil, nil
		}
	}()

	// Enable WAL and ensure it is set. New mode should be returned on success:
	// https://www.sqlite.org/pragma.html#pragma_journal_mode
	var mode string
	if err := db.db.QueryRowContext(ctx, `PRAGMA journal_mode = wal;`).Scan(&mode); err != nil {
		return err
	} else if mode != "wal" {
		return fmt.Errorf("enable wal failed, mode=%q", mode)
	}

	// Create a table to force writes to the WAL when empty.
	// There should only ever be one row with id=1.
	if _, err := db.db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS _litestream_seq (id INTEGER PRIMARY KEY, seq INTEGER);`); err != nil {
		return fmt.Errorf("create _litestream_seq table: %w", err)
	}

	// Create a lock table to force write locks during sync.
	// The sync write transaction always rolls back so no data should be in this table.
	if _, err := db.db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS _litestream_lock (id INTEGER);`); err != nil {
		return fmt.Errorf("create _litestream_lock table: %w", err)
	}

	// Start a long-running read transaction to prevent other transactions
	// from checkpointing.
	if err := db.acquireReadLock(ctx); err != nil {
		return fmt.Errorf("acquire read lock: %w", err)
	}

	// Read page size.
	if err := db.db.QueryRowContext(ctx, `PRAGMA page_size;`).Scan(&db.pageSize); err != nil {
		return fmt.Errorf("read page size: %w", err)
	} else if db.pageSize <= 0 {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check file system permissions and free disk space on the database volume; ensure the file is writable by the Litestream user.
  2. Ensure no other process holds the SQLite write lock (stop other writers or other litestream instances) and consider a busy_timeout.
  3. Verify the file is a valid SQLite database with `sqlite3 path 'PRAGMA integrity_check;'`.
  4. Re-open with a writable connection string/driver; if using litestream-yumrik/CGO-less driver, ensure the DSN does not set mode=ro.

Example fix

// before
litestream replicate -config /etc/litestream.yml   # db on read-only NFS mount -> fails
// after
mount -o rw ... /var/lib/app   # or chown litestream:litestream /var/lib/app/app.db
Defensive patterns

Strategy: try-catch

Validate before calling

// before opening with litestream
const os = require('os'); const fs = require('fs');
const st = fs.statSync(dbPath);
if (!fs.accessSync(dbPath, fs.constants.W_OK)) throw new Error('db not writable: ' + dbPath);
if (st.size > 0 && fs.readFileSync(dbPath).slice(0,15).toString() !== 'SQLite format 3') throw new Error('not a sqlite db');

Type guard

function isWritableSqliteFile(p) {
  try { const fd = fs.openSync(p, 'r+'); const buf = Buffer.alloc(16); fs.readSync(fd, buf, 0, 16, 0); fs.closeSync(fd); return buf.toString('latin1').startsWith('SQLite format 3'); }
  catch { return false; }
}

Try / catch

try {
  await db.Open(ctx);
} catch (err) {
  if (String(err.message).includes('create _litestream_seq table')) {
    // inspect err.cause: EACCES/ENOSPC/SQLITE_BUSY
    logger.error('litestream init failed on seq table', { cause: err.cause });
    // check disk space & permissions, then retry with backoff
  }
}

Prevention

When it happens

Trigger: Calling litestream replicate / Open on a database whose SQLite connection cannot execute the `CREATE TABLE IF NOT EXISTS _litestream_seq` statement: read-only database file or directory, disk full, corrupted schema, `database is locked` from another process holding a write lock, or a non-SQLite/invalid file at the configured path.

Common situations: Pointing Litestream at a database on a read-only mount or with wrong file permissions; another Litestream instance or heavy writer holding the write lock (SQLITE_BUSY); running out of disk space on the data volume; the path is not a valid SQLite database (e.g. empty or encrypted file).

Related errors


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