{"id":"9653dc156bfc3c7a","repo":"mongodb/node-mongodb-native","slug":"cannot-call-aborttransaction-twice","errorCode":null,"errorMessage":"Cannot call abortTransaction twice","messagePattern":"Cannot call abortTransaction twice","errorType":"exception","errorClass":"MongoTransactionError","httpStatus":null,"severity":"error","filePath":"src/sessions.ts","lineNumber":587,"sourceCode":"   *\n   * @param options - Optional options, can be used to override `defaultTimeoutMS`.\n   */\n  async abortTransaction(options?: { timeoutMS?: number }): Promise<void>;\n  /** @internal */\n  async abortTransaction(options?: { timeoutMS?: number; throwTimeout?: true }): Promise<void>;\n  async abortTransaction(options?: { timeoutMS?: number; throwTimeout?: true }): Promise<void> {\n    if (this.transaction.state === TxnState.NO_TRANSACTION) {\n      throw new MongoTransactionError('No transaction started');\n    }\n\n    if (this.transaction.state === TxnState.STARTING_TRANSACTION) {\n      // the transaction was never started, we can safely exit here\n      this.transaction.transition(TxnState.TRANSACTION_ABORTED);\n      return;\n    }\n\n    if (this.transaction.state === TxnState.TRANSACTION_ABORTED) {\n      throw new MongoTransactionError('Cannot call abortTransaction twice');\n    }\n\n    if (\n      this.transaction.state === TxnState.TRANSACTION_COMMITTED ||\n      this.transaction.state === TxnState.TRANSACTION_COMMITTED_EMPTY\n    ) {\n      throw new MongoTransactionError(\n        'Cannot call abortTransaction after calling commitTransaction'\n      );\n    }\n\n    const command: {\n      abortTransaction: 1;\n      writeConcern?: WriteConcernOptions;\n      recoveryToken?: Document;\n    } = { abortTransaction: 1 };\n\n    const timeoutMS =","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/sessions.ts#L569-L605","documentation":"Thrown by ClientSession.abortTransaction() when the transaction state is already TRANSACTION_ABORTED. Double-abort is rejected by the driver because the first abort already transitioned the state machine out of an abortable state. It is a MongoTransactionError.","triggerScenarios":"A catch block calls abortTransaction() and then a finally block calls abortTransaction() again; explicit abort followed by another explicit abort.","commonSituations":"Boilerplate try/catch/finally where both catch and finally abort; nested functions where each layer defensively aborts.","solutions":["Guard with active-state check: if (session.inTransaction()) await session.abortTransaction(). Note inTransaction() returns false once aborted, so this naturally prevents double-abort.","Centralize abort in one place (either catch or finally, not both).","Switch to withTransaction() to avoid manual abort management."],"exampleFix":"// before\ntry { session.startTransaction(); await coll.insertOne(doc, { session }); }\ncatch (e) { await session.abortTransaction(); throw e; }\nfinally { await session.abortTransaction(); } // throws: already aborted\n\n// after\ntry { session.startTransaction(); await coll.insertOne(doc, { session }); }\ncatch (e) { throw e; }\nfinally { if (session.inTransaction()) await session.abortTransaction(); }","handlingStrategy":"validation","validationCode":"if (session.inTransaction()) {\n  await session.abortTransaction(); // inTransaction() is false once aborted\n}","typeGuard":"function isAbortable(session: ClientSession): boolean {\n  return session.transaction.isActive;\n}","tryCatchPattern":"try {\n  await session.abortTransaction();\n} catch (e) {\n  if (e instanceof MongoTransactionError && /abortTransaction twice/.test(e.message)) {\n    // already aborted; safe to ignore\n  } else throw e;\n}","preventionTips":["Centralize abort in one location (catch OR finally, not both).","Always gate abort on session.inTransaction().","Use withTransaction() so abort is attempted at most once per attempt."],"tags":["sessions","transactions","state-machine","control-flow"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}