benbjohnson/litestream · error

invalid db page size

Error message

invalid db page size: %d

What it means

Litestream read a page size from `PRAGMA page_size` that is zero or negative, which is impossible for a valid SQLite database. Litestream rejects it because it cannot map database pages into WAL frames without a valid page size. This almost always means the file is not an initialized SQLite database or the header is corrupt.

Solutions

  1. Initialize the database first (let the application create its schema) before starting Litestream.
  2. If the file should be a valid DB, check its size and header: a valid SQLite file is a multiple of the page size and starts with 'SQLite format 3\000'.
  3. Restore the database from a backup or replica (`litestream restore`) if corrupted.
  4. Verify you configured the correct path in the config file.

Example fix

// before
# litestream.yml points at /data/app.db which is 0 bytes
// after
# start the app first so it creates the schema, then start litestream
systemctl start app && systemctl start litestream
Defensive patterns

Strategy: validation

Validate before calling

// verify before opening: initialized DB with nonzero size and page size
const st = fs.statSync(dbPath);
if (st.size === 0) throw new Error('db file is empty; initialize it before running litestream');
const out = execSync(`sqlite3 ${dbPath} 'PRAGMA page_size;'`).toString().trim();
if (!out || parseInt(out, 10) <= 0) throw new Error('invalid page size: ' + out);

Type guard

function isInitializedSqliteDb(p) {
  try { const b = fs.readFileSync(p).subarray(0, 16); return b.length === 16 && b.toString('latin1') === 'SQLite format 3\u0000'; } catch { return false; }
}

Try / catch

try {
  await db.Open(ctx);
} catch (err) {
  if (String(err.message).includes('invalid db page size')) {
    // file is empty or corrupt: run `litestream restore` or let the app initialize the schema first
  }
}

Prevention

When it happens

Trigger: db.init scans `PRAGMA page_size` into db.pageSize and the value is <= 0 — seen when the target file is empty (zero bytes), not yet initialized by SQLite, or its 100-byte header is zeroed/corrupted.

Common situations: Pointing Litestream at a path where the application hasn't created the database yet (empty file created by a touch or by the app but not initialized); copying an empty placeholder file; truncated/corrupted header after a crash on flaky storage.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at db.go:1105

	}

	// 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 {
		return fmt.Errorf("invalid db page size: %d", db.pageSize)
	}

	// Ensure meta directory structure exists.
	if err := internal.MkdirAll(db.metaPath, db.dirInfo); err != nil {
		return err
	}

	// Ensure WAL has at least one frame in it.
	if err := db.ensureWALExists(ctx); err != nil {
		return fmt.Errorf("ensure wal exists: %w", err)
	}

	// Check if database is behind replica (issue #781).
	// This must happen before replica.Start() to detect restore scenarios.
	if db.Replica != nil {
		if err := db.checkDatabaseBehindReplica(ctx); err != nil {
			return fmt.Errorf("check database behind replica: %w", err)
		}

View on GitHub (pinned to 4ed7a308f6)