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
- Check file system permissions and free disk space on the database volume; ensure the file is writable by the Litestream user.
- Ensure no other process holds the SQLite write lock (stop other writers or other litestream instances) and consider a busy_timeout.
- Verify the file is a valid SQLite database with `sqlite3 path 'PRAGMA integrity_check;'`.
- 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
- Ensure the Litestream user owns write access to the database file and directory.
- Monitor disk space on the data volume.
- Run only one Litestream process per database.
- Validate the file is a real SQLite DB before pointing Litestream at it.
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.