{"record":{"id":"5f02ff63c7e0f57e","repo":"tursodatabase/turso","slug":"database-is-closed","errorCode":null,"errorMessage":"Database is closed","messagePattern":"Database is closed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"bindings/react-native/src/Database.ts","lineNumber":480,"sourceCode":"    return !this._connection.getAutocommit();\n  }\n\n  /**\n   * Get last insert rowid\n   */\n  get lastInsertRowid(): number {\n    if (!this._connection) {\n      return 0;\n    }\n    return this._connection.lastInsertRowid();\n  }\n\n  /**\n   * Check if open and throw if not\n   */\n  private checkOpen(): void {\n    if (this._closed) {\n      throw new Error('Database is closed');\n    }\n    if (!this._connected || !this._connection) {\n      throw new Error('Database not connected. Call connect() first.');\n    }\n  }\n}\n","sourceCodeStart":462,"sourceCodeEnd":487,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/react-native/src/Database.ts#L462-L487","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ndb.close();\nawait db.query('SELECT 1'); // throws: Database is closed\n\n// after\nawait inFlightOps;\ndb.close();\ndb = new Database(opts); // if needed again\nawait db.connect();\nawait db.query('SELECT 1');","handlingStrategy":"try-catch","validationCode":"// Track lifecycle in your own wrapper — the binding's _closed is private\nclass DbManager {\n  private handle: Database | null = null;\n  get db(): Database {\n    if (!this.handle) throw new Error('Database closed — call open() first');\n    return this.handle;\n  }\n  async open(opts: DatabaseOpts) { this.handle = new Database(opts); await this.handle.connect(); }\n  async close() { await this.handle?.close(); this.handle = null; }\n}","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["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"],"tags":["react-native","lifecycle","use-after-close","database"],"backgroundTag":"use-after-close","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}