{"record":{"id":"4d23ebbd72cebb45","repo":"remix-run/remix","slug":"sqlite-database-cannot-method-while-transa","errorCode":null,"errorMessage":"SQLite database cannot ' + method + ' while transactions are open","messagePattern":"SQLite database cannot ' \\+ method \\+ ' while transactions are open","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/data-table-sqlite/src/lib/driver.ts","lineNumber":457,"sourceCode":"      this.#replaceDatabase()\n    } else {\n      // The supplied client remains caller-owned, but this wrapper cannot safely\n      // reuse a connection whose transaction state is unknown.\n      this.#databaseOpen = false\n    }\n  }\n\n  #configOrThrow(method: string): SqliteDatabaseConfig {\n    if (!this.#config) {\n      throw new Error('SQLite 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('SQLite database cannot ' + method + ' while transactions are open')\n    }\n  }\n\n  #assertTransaction(token: TransactionToken): void {\n    this.#assertDatabaseOpen()\n    if (!this.#transactions.has(token.id)) {\n      throw new Error('Unknown transaction token: ' + token.id)\n    }\n  }\n\n  #assertDatabaseOpen(): void {\n    if (!this.#databaseOpen) {\n      throw new Error('SQLite database is closed')\n    }\n  }\n}\n\nconst REMOVE_RETRIES = 10","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/data-table-sqlite/src/lib/driver.ts#L439-L475","documentation":"The SQLite driver blocks lifecycle operations (wipe, close) while transactions remain open, throwing from #assertNoOpenTransactions when the transactions map is non-empty — same protection as the Postgres driver, preventing resets that would corrupt in-flight work.","triggerScenarios":"Calling wipe() or close() after a beginTransaction without a matching commit/rollback; leaked tokens from early returns; a still-running async operation holding a transaction during test teardown.","commonSituations":"Test teardown wiping SQLite while queries are pending; error paths that begin but never roll back; close() in a process shutdown hook racing in-flight transactions.","solutions":["Guarantee commit/rollback in try/finally around every transaction, or use the managed transaction API","Await all in-flight work before wipe()/close()","In tests, use per-test drivers or ensure afterAll ordering runs after transactions settle"],"exampleFix":"// before\nlet tx = await db.beginTransaction()\n// leaked on early return\nawait db.wipe() // throws\n\n// after\nlet tx = await db.beginTransaction()\ntry { await work(tx); await db.commitTransaction(tx) }\ncatch (e) { await db.rollbackTransaction(tx); throw e }","handlingStrategy":"validation","validationCode":"// drain before teardown\nawait Promise.allSettled(pendingTransactionWork)\nawait db.wipe()","typeGuard":null,"tryCatchPattern":"try { await db.close() } catch (e) { if (e instanceof Error && e.message.includes('while transactions are open')) { /* settle or force-rollback open transactions, then retry */ } throw e }","preventionTips":["try/finally around every transaction","Await in-flight work in beforeAll/beforeExit hooks","Use managed transactions everywhere"],"tags":["sqlite","transaction","lifecycle","driver"],"backgroundTag":"open-transactions-block-operation","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}