tursodatabase/turso · error · TypeError
The database connection is not open
Error message
The database connection is not open
What it means
Thrown by Database.prepare() in the better-sqlite3 compatibility layer when you try to prepare a statement on a connection whose native handle is no longer open. The `open` property is a live getter over the native database, so once close() has been called (or the connection was never successfully opened), any subsequent prepare() is rejected immediately with this TypeError instead of crashing the native layer.
Source
Thrown at bindings/javascript/packages/common/compat.ts:159
this.db.connectSync();
Object.defineProperties(this, {
name: { get: () => this.db.path },
readonly: { get: () => this.db.readonly },
open: { get: () => this.db.open },
memory: { get: () => this.db.memory },
inTransaction: { get: () => this.db.inTransaction() },
});
}
/**
* Prepares a SQL statement for execution.
*
* @param {string} sql - The SQL statement string to prepare.
*/
prepare(sql) {
if (!this.open) {
throw new TypeError("The database connection is not open");
}
if (!sql) {
throw new RangeError("The supplied SQL string contains no statements");
}
try {
return new Statement(this.db.prepare(sql), this.db);
} catch (err) {
throw convertError(err);
}
}
/**
* Returns a function that executes the given function in a transaction.
*
* @param {function} fn - The function to wrap in a transaction.
*/
transaction(fn) {View on GitHub (pinned to bad083fafb)
Solutions
- Check `db.open` before preparing: if (db.open) stmt = db.prepare(sql)
- Reorder shutdown: drain in-flight queries first, then close the connection (or use an async-dispose queue)
- If the connection was closed unexpectedly, reopen it (recreate the Database) and retry the operation
- Audit for double-close or premature close paths (SIGINT handlers, test teardown, connection-pool eviction)
Example fix
// before
const row = db.prepare('SELECT 1').get(); // db was closed earlier
// after
if (!db.open) db = new Database(...); // or skip/reopen
const row = db.prepare('SELECT 1').get(); Defensive patterns
Strategy: validation
Validate before calling
if (!db.open) {
throw new Error('database is closed; reopen before preparing statements');
}
const stmt = db.prepare(sql); Type guard
function isOpen(db: { open: boolean }): boolean {
return db.open === true;
} Try / catch
try {
stmt = db.prepare(sql);
} catch (err) {
if (err instanceof TypeError && err.message === 'The database connection is not open') {
db = new Database(path); // or mark connection stale and reschedule
stmt = db.prepare(sql);
} else {
throw err;
}
} Prevention
- Own the connection in one place; never let unrelated modules call close()
- Check db.open before any prepare/exec/batch in queue workers and timers
- Drain in-flight work before closing during shutdown
- In tests, create and close the Database within the same suite lifecycle
When it happens
Trigger: Calling db.prepare(sql) after db.close(); calling prepare() during shutdown of a long-lived process (e.g. after a SIGTERM handler closed the DB but a queued query still runs); sharing a Database instance across modules where one path closes it; calling prepare() after an unrecoverable native error closed the connection.
Common situations: Unit tests that close the DB in afterEach but a stray test still queries it; hot-reload in dev servers that closes the old connection while in-flight requests still hold a reference to the old Database object; graceful-shutdown code that closes the DB before draining the request queue.
Related errors
- The supplied SQL string contains no statements
- Expected first argument to be a function
- Expected first argument to be a string
- Expected second argument to be an options object
- not implemented
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/5148e5cc335f4d8c.
Report an issue: GitHub.