payloadcms/payload · critical · Error
Error: cannot connect to SQLite: ${message}
Error message
Error: cannot connect to SQLite: ${message} What it means
Thrown by the SQLite (db-sqlite) adapter's `connect` after `better-sqlite3` fails to open the database. The adapter logs the message, rejects the init promise, and re-throws a wrapped Error so `payload.init()` rejects.
Source
Thrown at packages/db-sqlite/src/connect.ts:57
}
const logger = this.logger || false
this.drizzle = drizzle(this.client, { logger, schema: this.schema })
if (!hotReload) {
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
this.payload.logger.info(`---- DROPPING TABLES ----`)
await this.dropDatabase({ adapter: this })
this.payload.logger.info('---- DROPPED TABLES ----')
}
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err)
this.payload.logger.error({ err, msg: `Error: cannot connect to SQLite: ${message}` })
if (typeof this.rejectInitializing === 'function') {
this.rejectInitializing()
}
throw new Error(`Error: cannot connect to SQLite: ${message}`)
}
// Only push schema if not in production
if (
process.env.NODE_ENV !== 'production' &&
process.env.PAYLOAD_MIGRATING !== 'true' &&
this.push !== false
) {
await pushDevSchema(this as unknown as DrizzleAdapter)
}
if (typeof this.resolveInitializing === 'function') {
this.resolveInitializing()
}
if (process.env.NODE_ENV === 'production' && this.prodMigrations) {
await this.migrate({ migrations: this.prodMigrations as Migration[] })
}View on GitHub (pinned to 00c58b35c0)
Solutions
- Make `dbPath` absolute and confirm its parent directory exists and is writable.
- Rebuild the native binding for your Node ABI: `npm rebuild better-sqlite3` (or reinstall).
- Ensure no other process holds an exclusive lock on the file.
- On serverless/read-only filesystems, place the DB on a writable volume.
Example fix
// before
sqliteAdapter({ client: { url: file:./db.sqlite } }) // relative, dir missing
// after
import { mkdirSync } from 'fs'
mkdirSync('/data', { recursive: true })
sqliteAdapter({ client: { url: 'file:/data/db.sqlite' } }) Defensive patterns
Strategy: validation
Validate before calling
function assertSqliteWritable(dbPath) {
const dir = path.dirname(path.resolve(dbPath))
fs.mkdirSync(dir, { recursive: true })
fs.accessSync(dir, fs.constants.W_OK)
} Type guard
const isAbsoluteWritablePath = (p) => path.isAbsolute(p)
Try / catch
try { await payload.init() }
catch (e) { if (/cannot connect to SQLite/.test(e.message)) { await rebuildBetterSqlite() } else throw e } Prevention
- Use an absolute dbPath and ensure its directory exists and is writable.
- After Node upgrades, run `npm rebuild better-sqlite3`.
- Avoid placing the SQLite file on a read-only filesystem.
- Ensure no other process holds an exclusive lock on the file.
When it happens
Trigger: The SQLite file path is unwritable or its directory doesn't exist, the file is locked by another process, the native binding is missing/incompatible (Node ABI mismatch), or the file is corrupt.
Common situations: Relative or wrong `dbPath`; target directory missing or read-only; file permissions; Node version vs better-sqlite3 prebuilt binary mismatch; file on a read-only/serverless filesystem; another process holds an exclusive lock.
Related errors
- Error: cannot connect to Postgres: ${err.message}
- Error: cannot connect to Postgres: ${err.message}
- Error: missing MongoDB connection URL.
- beginTransaction called while no connection to the database
- Operator handler "${handler.name}" requires the "${extension
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/f37ea7dd6a14fb65.
Report an issue: GitHub.