{"record":{"id":"b8d4408c0ecf262d","repo":"remix-run/remix","slug":"mysql-database-cannot-method-while-transacti","errorCode":null,"errorMessage":"MySQL database cannot  + method +  while transactions are open","messagePattern":"MySQL database cannot  \\+ method \\+  while transactions are open","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/data-table-mysql/src/lib/driver.ts","lineNumber":485,"sourceCode":"    await this.#closePool().catch(() => undefined)\n\n    if (this.#config) {\n      this.#client = createMysqlPool(this.#config)\n      this.#poolClosed = false\n    }\n  }\n\n  #configOrThrow(method: string): string | MysqlPoolOptions {\n    if (!this.#config) {\n      throw new Error('MySQL database ' + method + '() requires config-based construction')\n    }\n\n    return this.#config\n  }\n\n  #assertNoOpenTransactions(method: string): void {\n    if (this.#transactions.size > 0) {\n      throw new Error('MySQL database cannot ' + method + ' while transactions are open')\n    }\n  }\n\n  #resolveClient(token: TransactionToken | undefined): MysqlQueryable {\n    if (!token) {\n      return this.#client\n    }\n\n    return this.#transactionConnection(token)\n  }\n\n  #transactionConnection(token: TransactionToken): MysqlTransactionConnection {\n    let transaction = this.#transactions.get(token.id)\n\n    if (!transaction) {\n      throw new Error('Unknown transaction token: ' + token.id)\n    }\n","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/data-table-mysql/src/lib/driver.ts#L467-L503","documentation":"The driver refuses destructive lifecycle operations (wipe, close) while transactions are still open, tracked in its internal #transactions map. #assertNoOpenTransactions throws with the offending method name to prevent dropping or wiping a database with in-flight transactions that would be left in limbo.","triggerScenarios":"Calling driver.wipe() or driver.close() after beginTransaction without a matching commit/rollback; test teardown wiping the database while a leaked transaction token was never finalized.","commonSituations":"Test suites that begin transactions and error out before finalization, then wipe between tests; missing rollback in a catch block; async operations still in flight when close() is called during shutdown.","solutions":["Commit or roll back every outstanding transaction before calling wipe()/close()","Use try/finally around transaction bodies so errors always roll back","In test teardown, drain or assert zero open transactions before wiping"],"exampleFix":"// before\nconst token = await driver.beginTransaction()\nawait doWork(driver, token)\n// error path skips commit\nawait driver.wipe() // throws\n// after\nconst token = await driver.beginTransaction()\ntry {\n  await doWork(driver, token)\n  await driver.commitTransaction(token)\n} catch (e) {\n  await driver.rollbackTransaction(token)\n  throw e\n}\nawait driver.wipe()","handlingStrategy":"try-catch","validationCode":"// Ensure finalization in a helper\nasync function withTransaction<T>(driver, fn: (t: TransactionToken) => Promise<T>) {\n  const token = await driver.beginTransaction()\n  try { const r = await fn(token); await driver.commitTransaction(token); return r }\n  catch (e) { await driver.rollbackTransaction(token); throw e }\n}","typeGuard":null,"tryCatchPattern":"try { await driver.wipe() } catch (e) { if (e instanceof Error && e.message.includes('while transactions are open')) { /* finalize leaked transactions, then retry */ } throw e }","preventionTips":["Always pair beginTransaction with try/finally finalization","Assert no open transactions before teardown in tests"],"tags":["data-table","mysql","transaction","lifecycle"],"backgroundTag":"open-transactions-block-lifecycle","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}