remix-run/remix · error · Error

Unknown transaction token: + token.id

Error message

Unknown transaction token: + token.id

What it means

The Postgres driver keeps an internal map of open transactions keyed by token id. commitTransaction throws this when the supplied TransactionToken is not in that map — i.e. the transaction was already committed/rolled back, was created by a different driver instance, or the token was fabricated.

Source

Thrown at packages/data-table-postgres/src/lib/driver.ts:230

    this.#transactions.set(token.id, {
      client: transactionClient,
      releaseOnClose,
    })

    return token
  }

  /**
   * Commits an open postgres transaction.
   * @param token Transaction token to commit.
   * @returns A promise that resolves when the transaction is committed.
   */
  async commitTransaction(token: TransactionToken): Promise<void> {
    let transaction = this.#transactions.get(token.id)

    if (!transaction) {
      throw new Error('Unknown transaction token: ' + token.id)
    }

    let failure: unknown
    try {
      await transaction.client.query('commit')
    } catch (error) {
      failure = error
      throw error
    } finally {
      this.#transactions.delete(token.id)

      if (transaction.releaseOnClose) {
        if (failure === undefined) {
          releasePostgresClient(transaction.client)
        } else {
          destroyPostgresClient(transaction.client, failure)
        }
      }

View on GitHub (pinned to 9696913134)

Solutions

  1. Ensure commit/rollback is called exactly once per transaction token; clear the token reference afterwards
  2. Use the driver's transaction helper (e.g. database.transaction(async tx => ...)) which manages the token lifecycle instead of manual begin/commit
  3. Verify you are passing the token returned by beginTransaction on the same driver instance
  4. Guard with hasOpenTransactions/driver state checks before manual commit if lifecycle is uncertain

Example fix

// before
await driver.commitTransaction(token)
// ... later, in an error handler
await driver.commitTransaction(token) // throws

// after
let done = false
try {
  await driver.commitTransaction(token)
  done = true
} finally {
  if (!done) await driver.rollbackTransaction(token).catch(() => undefined)
}
Defensive patterns

Strategy: try-catch

Try / catch

try { await driver.commitTransaction(token) } catch (e) { if (e instanceof Error && e.message.startsWith('Unknown transaction token')) { /* already finished — treat as success */ return } throw e }

Prevention

When it happens

Trigger: Calling commitTransaction twice with the same token; committing after rollbackTransaction already removed it; using a token from one PostgresDatabase instance on another; keeping a token across driver close()/wipe() which clears transactions.

Common situations: Retry logic that re-commits on timeout; storing transaction tokens in shared state or caches; running tests that reuse a module-level driver but per-test tokens (or vice versa); committing after an error path already rolled back.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/bf65de0f0708f9c8. Report an issue: GitHub.