{"record":{"id":"b6cd5e5be17df387","repo":"tursodatabase/turso","slug":"the-database-connection-is-not-open-b6cd5e","errorCode":null,"errorMessage":"The database connection is not open","messagePattern":"The database connection is not open","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"serverless/javascript/src/connection.ts","lineNumber":153,"sourceCode":"  /**\n   * Prepare a SQL statement for execution.\n   * \n   * Prepared statements created from a Connection use the same underlying session so transaction boundaries are preserved.\n   * This method fetches column metadata using the describe functionality.\n   * \n   * @param sql - The SQL statement to prepare\n   * @returns A Promise that resolves to a Statement object with column metadata\n   * \n   * @example\n   * ```typescript\n   * const stmt = await client.prepare(\"SELECT * FROM users WHERE id = ?\");\n   * const columns = stmt.columns();\n   * const user = await stmt.get([123]);\n   * ```\n   */\n  async prepare(sql: string): Promise<Statement> {\n    if (!this.isOpen) {\n      throw new TypeError(\"The database connection is not open\");\n    }\n\n    // Describe on the existing session so it sees uncommitted DDL\n    // (e.g. CREATE TABLE in the same transaction).\n    await this.execLock.acquire();\n    let description;\n    try {\n      description = await this.session.describe(sql);\n    } finally {\n      this.execLock.release();\n    }\n\n    const stmt = Statement.fromSession(this.session, sql, description.cols, this.execLock);\n    if (this.defaultSafeIntegerMode) {\n      stmt.safeIntegers(true);\n    }\n    return stmt;\n  }","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/javascript/src/connection.ts#L135-L171","documentation":"Connection.prepare() checks the private isOpen flag and throws a plain TypeError 'The database connection is not open' when the connection has been closed. close() sets isOpen = false before closing the session, and there is no public isOpen getter on Connection, so callers must track lifecycle themselves or use reconnect() to reopen the same object.","triggerScenarios":"await db.close(); await db.prepare(sql). Reusing a pooled Connection object after a maintenance path closed it. An error path closing the connection, then normal flow continuing to prepare statements.","commonSituations":"Connection pools that close idle connections but hand them out again; retry logic that closes on a network error and later prepares; long-lived server code where a shutdown hook closed the connection before late requests arrive.","solutions":["Call await db.reconnect() to reopen the same Connection object, then retry prepare()","Create a new Connection via connect(config) instead of reusing the closed one","Remove Connection objects from your pool/registry when you close them so they are never handed out again","Ensure close() only runs after all users of the connection are finished"],"exampleFix":"// before\nawait db.close();\nconst stmt = await db.prepare('SELECT * FROM users WHERE id = ?');\n// TypeError: The database connection is not open\n\n// after\nif (connectionWasClosed) {\n  await db.reconnect();\n}\nconst stmt = await db.prepare('SELECT * FROM users WHERE id = ?');","handlingStrategy":"try-catch","validationCode":"// Connection exposes no public isOpen getter — track lifecycle at the call site.\nlet db = connect(config);\nlet dbOpen = true;\n\nasync function closeDb() {\n  await db.close();\n  dbOpen = false;\n}\n\nasync function prepareSafe(sql: string) {\n  if (!dbOpen) {\n    await db.reconnect();\n    dbOpen = true;\n  }\n  return db.prepare(sql);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await db.prepare(sql);\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('not open')) {\n    await db.reconnect();\n    return db.prepare(sql);\n  }\n  throw e;\n}","preventionTips":["Wrap close() in a helper that also removes the Connection from any pool or registry","Use await db.reconnect() to reopen rather than reusing a closed object implicitly","Apply pragmas and prepare statements right after connect so lifecycle is linear","In pools, hand out only connections you have not marked closed"],"tags":["lifecycle","connection-closed","prepared-statements","use-after-close"],"backgroundTag":"use-after-close","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}