tursodatabase/turso · error · Error
Database is closed
Error message
Database is closed
What it means
checkOpen() is the private precondition for query/exec flows on the React Native Database and throws 'Database is closed' when _closed is true — i.e., after close() was called. Everything on the instance becomes unusable from that point, including prepared-statement operations that route through the connection. The database cannot be reopened; construct a new Database instead.
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 bad083fafb)
Solutions
- Create a fresh Database instance (and connect()) after closing — close() is terminal for the handle
- Await all in-flight operations before calling close(), and null out references so stale closures cannot use the handle
- Track lifecycle state in your own wrapper (open/connect/close) and check it before issuing queries
Example fix
// before
db.close();
await db.query('SELECT 1'); // throws: Database is closed
// after
await inFlightOps;
db.close();
db = new Database(opts); // if needed again
await db.connect();
await db.query('SELECT 1'); Defensive patterns
Strategy: try-catch
Validate before calling
// Track lifecycle in your own wrapper — the binding's _closed is private
class DbManager {
private handle: Database | null = null;
get db(): Database {
if (!this.handle) throw new Error('Database closed — call open() first');
return this.handle;
}
async open(opts: DatabaseOpts) { this.handle = new Database(opts); await this.handle.connect(); }
async close() { await this.handle?.close(); this.handle = null; }
} Try / catch
try { await db.query(sql); } catch (e) { if (e instanceof Error && e.message === 'Database is closed') { db = await openDatabase(opts); return db.query(sql); } throw e; } Prevention
- Null out database references after close() so stale closures fail your own guard first
- Await pending operations before closing on unmount/logout
- close() is terminal — always construct a new Database to reopen
When it happens
Trigger: Calling `db.query(...)`, `db.exec(...)`, or preparing a statement after `db.close()`; React component unmount closing the DB while an in-flight sibling operation or a later user action still uses the handle; shutdown hooks closing the database before a final flush completes.
Common situations: App shutdown or logout flows that close eagerly; StrictMode double-mounts in React 18 closing on cleanup while another effect still queries; long-lived singletons captured in closures that outlive the close; error-recovery code that closes on failure but retry paths reuse the handle.
Related errors
- push() is only available for sync databases
- pull() is only available for sync databases
- stats() is only available for sync databases
- Database not connected. Call connect() first.
- CLIENT_CLOSED
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/5f02ff63c7e0f57e.
Report an issue: GitHub.