mongodb/node-mongodb-native · error · MongoTransactionError

Transaction already in progress

Error message

Transaction already in progress

What it means

`startTransaction` throws MongoTransactionError when `inTransaction()` is already true — a session hosts at most one transaction at a time. The check protects transaction state from being overwritten mid-flight.

Solutions

  1. Commit or abort before starting again: `await session.commitTransaction()` or `await session.abortTransaction()`.
  2. Prefer `session.withTransaction(async (s) => { ... })` — it manages start/commit/abort/retry for you.
  3. Always pair start with a finally block: `try { session.startTransaction(); ... await session.commitTransaction(); } catch { await session.abortTransaction(); throw; }`.

Example fix

// before
session.startTransaction();
await collection.insertOne(doc, { session });
session.startTransaction(); // throws

// after
await session.withTransaction(async (s) => {
  await collection.insertOne(doc, { session: s });
});
Defensive patterns

Strategy: validation

Validate before calling

function safeStart(session, opts) {
  if (session.inTransaction()) {
    throw new Error('transaction already in progress; commit or abort first');
  }
  session.startTransaction(opts);
}

Type guard

function canStartTxn(session) {
  return !session.inTransaction();
}

Prevention

When it happens

Trigger: `session.startTransaction(); ... session.startTransaction();` without an intervening commit or abort; control-flow bug where startTransaction is called in a loop body unconditionally.

Common situations: Refactoring a sequential flow into a loop and forgetting to commit/abort each iteration; calling withTransaction and also manually calling startTransaction inside the callback; error paths that skip abort.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/af599726e0497d78. Report an issue: GitHub.

Appendix: source

Thrown at src/sessions.ts:394

  }

  /**
   * Starts a new transaction with the given options.
   *
   * @remarks
   * **IMPORTANT**: Running operations in parallel is not supported during a transaction. The use of `Promise.all`,
   * `Promise.allSettled`, `Promise.race`, etc to parallelize operations inside a transaction is
   * undefined behaviour.
   *
   * @param options - Options for the transaction
   */
  startTransaction(options?: TransactionOptions): void {
    if (this.snapshotEnabled) {
      throw new MongoCompatibilityError('Transactions are not supported in snapshot sessions');
    }

    if (this.inTransaction()) {
      throw new MongoTransactionError('Transaction already in progress');
    }

    if (this.isPinned && this.transaction.isCommitted) {
      this.unpin();
    }

    this.commitAttempted = false;
    // increment txnNumber
    this.incrementTransactionNumber();
    // create transaction state
    this.transaction = new Transaction({
      readConcern:
        options?.readConcern ??
        this.defaultTransactionOptions.readConcern ??
        this.clientOptions?.readConcern,
      writeConcern:
        options?.writeConcern ??
        this.defaultTransactionOptions.writeConcern ??

View on GitHub (pinned to dce7939f86)