mongodb/node-mongodb-native · error · MongoTransactionError
Transaction already in progress
Error message
Transaction already in progress
What it means
Thrown by ClientSession.startTransaction() when a transaction is already active on the session (state is STARTING_TRANSACTION or TRANSACTION_IN_PROGRESS). The driver enforces one active transaction per session per the sessions spec. It is a MongoTransactionError.
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 3366c21a63)
Solutions
- Commit or abort the existing transaction before starting a new one: await session.abortTransaction() then session.startTransaction().
- Check state first: if (!session.inTransaction()) session.startTransaction().
- Use withTransaction() which manages start/commit/abort lifecycle internally instead of calling startTransaction yourself.
- Audit helper functions to ensure only one layer owns transaction begin/commit.
Example fix
// before
session.startTransaction();
// ... later, branch re-enters
session.startTransaction(); // throws
// after
if (!session.inTransaction()) {
session.startTransaction();
} Defensive patterns
Strategy: validation
Validate before calling
if (!session.inTransaction()) {
session.startTransaction();
} Type guard
function isTransactionFree(session: ClientSession): boolean {
return !session.inTransaction();
} Try / catch
try {
session.startTransaction();
} catch (e) {
if (e instanceof MongoTransactionError && /already in progress/.test(e.message)) {
// abort or commit the existing one first
await session.abortTransaction();
session.startTransaction();
} else throw e;
} Prevention
- Always check session.inTransaction() before calling startTransaction().
- Prefer withTransaction() over manual start/commit/abort.
- Ensure only one layer of your code owns transaction begin.
When it happens
Trigger: Two consecutive calls to session.startTransaction() with no intervening commitTransaction/abortTransaction; a re-entrant helper that starts a transaction while the caller already did.
Common situations: Refactoring code so a transaction is started both outside and inside a function; retry loops that restart a transaction without aborting the previous one; copy-paste of startTransaction boilerplate.
Related errors
- No transaction started
- Cannot call commitTransaction after calling abortTransaction
- Cannot call abortTransaction twice
- Cannot call abortTransaction after calling commitTransaction
- Function provided to `withTransaction` must return a Promise
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/af599726e0497d78.json.
Report an issue: GitHub.