tursodatabase/turso · error · Error
Database is closed
Error message
Database is closed
What it means
checkOpen() throws this when _closed is true — i.e. after db.close() ran. close() closes the native connection and database handles and sets _closed last, so every later prepare(), exec(), transaction, or getter that routes through checkOpen() fails fast instead of touching freed native resources.
Solutions
- Check `db.open` before issuing statements after any point where close() may have run
- Reopen by constructing a new Database instance and awaiting connect() rather than reusing the closed one
- Cancel/await in-flight work before close() so nothing enqueues queries afterward
- On logout flows, null out module-level db references after close() so stale callers fail visibly in dev
Example fix
// before
let db = new Database({ path: getDbPath('app.db') });
await db.connect();
// later, after logout:
db.close();
const rows = await db.all('SELECT 1'); // throws 'Database is closed'
// after
if (!db.open) {
db = new Database({ path: getDbPath('app.db') });
await db.connect();
}
const rows = await db.all('SELECT 1'); Defensive patterns
Strategy: validation
Validate before calling
if (!db.open) {
db = new Database({ path: getDbPath('app.db') });
await db.connect();
}
await db.prepare('SELECT 1'); Type guard
function isOpen(db: Database): boolean {
return db.open; // false once close() ran
} Try / catch
try {
await db.prepare(sql);
} catch (e) {
if (e instanceof Error && e.message === 'Database is closed') {
db = await reopenDatabase(); // fresh instance + connect
return db.prepare(sql);
}
throw e;
} Prevention
- Null out Database references after close() so stale callers fail visibly in development
- Await pending work before closing; close exactly once at real teardown
- Check db.open before queries in code that may run after logout/background expiry
When it happens
Trigger: Calling db.prepare(sql), db.exec(sql), db.transaction(...), etc. after db.close() has already executed; a late async operation (queued query, retry timer, background sync loop) firing after the shutdown path closed the database.
Common situations: Closing the db in a component unmount / app exit handler while other code still holds a reference and issues queries; test files closing a shared database in afterEach but reusing it in a later test; caching a Database in a module-level variable that survives logout/login cycles where logout closes it.
Related errors
- Database not connected. Call connect() first.
- No connection available
- Statement has been finalized
- statement is closed
- Statement is closed
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/5f02ff63c7e0f57e.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/react-native/src/Database.ts:480
return !this._connection.getAutocommit();
}
/**
* Get last insert rowid
*/
get lastInsertRowid(): number {
if (!this._connection) {
return 0;
}
return this._connection.lastInsertRowid();
}
/**
* Check if open and throw if not
*/
private checkOpen(): void {
if (this._closed) {
throw new Error('Database is closed');
}
if (!this._connected || !this._connection) {
throw new Error('Database not connected. Call connect() first.');
}
}
}
View on GitHub (pinned to 244cde92a7)