{"record":{"id":"47b9cf2bc42873ec","repo":"mongodb/node-mongodb-native","slug":"cannot-call-aborttransaction-after-calling-committ","errorCode":null,"errorMessage":"Cannot call abortTransaction after calling commitTransaction","messagePattern":"Cannot call abortTransaction after calling commitTransaction","errorType":"exception","errorClass":"MongoTransactionError","httpStatus":null,"severity":"error","filePath":"src/sessions.ts","lineNumber":594,"sourceCode":"    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 =\n      typeof options?.timeoutMS === 'number'\n        ? options.timeoutMS\n        : this.timeoutContext?.csotEnabled()\n          ? this.timeoutContext.timeoutMS // refresh timeoutMS for abort operation\n          : typeof this.timeoutMS === 'number'\n            ? this.timeoutMS\n            : null;","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/sessions.ts#L576-L612","documentation":"`abortTransaction` throws MongoTransactionError when the state is `TRANSACTION_COMMITTED` or `TRANSACTION_COMMITTED_EMPTY` — once commit has been attempted you cannot abort that transaction. The commit's outcome must be resolved (possibly retried), not overturned by an abort.","triggerScenarios":"`session.startTransaction(); ... await session.commitTransaction(); await session.abortTransaction();` — commonly a commit-then-catch that decides to abort after the commit already ran.","commonSituations":"A catch block that aborts without checking whether the try block already committed; retry loops that abort after a failed commit attempt; misordered cleanup in a wrapper.","solutions":["Only abort if the transaction is still in progress: `if (session.inTransaction()) await session.abortTransaction();`.","Do not abort after commit has been called — handle commit failures via retry/error labels instead.","Adopt `withTransaction` for commit/retry logic and reserve manual abort for the callback body."],"exampleFix":"// before\ntry {\n  session.startTransaction();\n  await collection.insertOne(doc, { session });\n  await session.commitTransaction();\n} catch (err) {\n  await session.abortTransaction(); // throws if commit already ran\n  throw err;\n}\n\n// after\ntry {\n  session.startTransaction();\n  await collection.insertOne(doc, { session });\n  await session.commitTransaction();\n} catch (err) {\n  if (session.inTransaction()) await session.abortTransaction();\n  throw err;\n}","handlingStrategy":"validation","validationCode":"function safeAbort(session) {\n  // abort is only valid while the transaction is still in progress\n  if (session.inTransaction()) return session.abortTransaction();\n}","typeGuard":"function canAbortTxn(session) {\n  return session.inTransaction();\n}","tryCatchPattern":null,"preventionTips":["Do not abort after commit has been called; handle commit failures via retry/labels instead.","Guard cleanup with `if (session.inTransaction())`.","Centralise transaction cleanup in one helper to avoid divergent paths."],"tags":["sessions","transactions","validation","state","lifecycle"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}