{"id":"5c6c77358667c37c","repo":"mongodb/node-mongodb-native","slug":"cannot-call-committransaction-after-calling-abortt","errorCode":null,"errorMessage":"Cannot call commitTransaction after calling abortTransaction","messagePattern":"Cannot call commitTransaction after calling abortTransaction","errorType":"exception","errorClass":"MongoTransactionError","httpStatus":null,"severity":"error","filePath":"src/sessions.ts","lineNumber":444,"sourceCode":"   *\n   * @param options - Optional options, can be used to override `defaultTimeoutMS`.\n   */\n  async commitTransaction(options?: { timeoutMS?: number }): Promise<void> {\n    if (this.transaction.state === TxnState.NO_TRANSACTION) {\n      throw new MongoTransactionError('No transaction started');\n    }\n\n    if (\n      this.transaction.state === TxnState.STARTING_TRANSACTION ||\n      this.transaction.state === TxnState.TRANSACTION_COMMITTED_EMPTY\n    ) {\n      // the transaction was never started, we can safely exit here\n      this.transaction.transition(TxnState.TRANSACTION_COMMITTED_EMPTY);\n      return;\n    }\n\n    if (this.transaction.state === TxnState.TRANSACTION_ABORTED) {\n      throw new MongoTransactionError(\n        'Cannot call commitTransaction after calling abortTransaction'\n      );\n    }\n\n    const command: {\n      commitTransaction: 1;\n      writeConcern?: WriteConcernSettings;\n      recoveryToken?: Document;\n      maxTimeMS?: number;\n    } = { commitTransaction: 1 };\n\n    const timeoutMS =\n      typeof options?.timeoutMS === 'number'\n        ? options.timeoutMS\n        : typeof this.timeoutMS === 'number'\n          ? this.timeoutMS\n          : null;\n","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/sessions.ts#L426-L462","documentation":"Thrown by ClientSession.commitTransaction() when the transaction state is TRANSACTION_ABORTED. Once a transaction is aborted it cannot be committed; the spec forbids this transition. It is a MongoTransactionError.","triggerScenarios":"Calling commitTransaction() after abortTransaction() has already run on the same transaction; an error handler aborts and execution then falls through to a commit in the success/finally path.","commonSituations":"try { start; ops } catch { await abort } finally { await commit } - the finally re-attempts commit after the catch aborted; nested try blocks where the inner aborts but outer commits.","solutions":["Track whether abort already ran and skip commit: only commit when state is STARTING_TRANSACTION/TRANSACTION_IN_PROGRESS.","Use withTransaction() so the driver handles abort/commit transitions correctly.","Reorder control flow so abort and commit are mutually exclusive branches (commit on success path, abort on error path)."],"exampleFix":"// before\ntry {\n  session.startTransaction();\n  await coll.insertOne(doc, { session });\n} catch (e) {\n  await session.abortTransaction();\n  throw e;\n} finally {\n  await session.commitTransaction(); // throws after abort\n}\n\n// after\ntry {\n  session.startTransaction();\n  await coll.insertOne(doc, { session });\n  await session.commitTransaction();\n} catch (e) {\n  if (session.inTransaction()) await session.abortTransaction();\n  throw e;\n}","handlingStrategy":"validation","validationCode":"// only commit from the success path, when still active\nif (session.inTransaction()) {\n  await session.commitTransaction();\n}","typeGuard":"function isCommittable(session: ClientSession): boolean {\n  return session.transaction.isActive; // STARTING or IN_PROGRESS\n}","tryCatchPattern":"try {\n  await session.commitTransaction();\n} catch (e) {\n  if (e instanceof MongoTransactionError && /after calling abortTransaction/.test(e.message)) {\n    // already aborted; swallow\n  } else throw e;\n}","preventionTips":["Never call commitTransaction from a finally that also runs after abort.","Restrict commit to the success branch and abort to the error branch.","Track an 'aborted' boolean in scope to short-circuit commit."],"tags":["sessions","transactions","state-machine","control-flow"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}