Download

WriteConflict: Please retry your operation or multi-document transaction

Two transactions changed the same document at the same time; the one that got there second is aborted with WriteConflict and the TransientTransactionError label. Retry the whole transaction (withTransaction does it for you) and keep transactions short.

MongoDB error 112· Tested on MongoDB 8.0.32 replica set (mongosh 2.12.0; Node.js driver 6.20.0)· Updated 11 October 2026

Caused by :: Write conflict during plan execution and yielding is disabled. :: Please retry your operation or multi-document transaction.

What it means

Inside a transaction, the first write to a document holds on to it until the transaction commits or aborts. When a second transaction tries to change the same document in that time, MongoDB doesn’t make it wait: it fails the write at once with code 112, WriteConflict, and aborts that transaction. The error carries the label TransientTransactionError, which means “retrying the whole transaction may work”.

The message has varied between versions; MongoDB 8.0 says:

Caused by :: Write conflict during plan execution and yielding is disabled. :: Please retry your operation or multi-document transaction.

Older versions said WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction. After the conflict the transaction is gone, so further commands in it fail with code 251, NoSuchTransaction: Transaction with { txnNumber: 1 } has been aborted.

A transaction also gets this error when it writes a document that a write outside any transaction changed after the transaction began. Writes outside transactions never get it themselves: one that reaches a document a transaction has already changed waits until the transaction ends (or until its own time limit runs out).

Common causes

  1. Two requests change the same document at once, each in a transaction: a counter, a balance, a stock level, a shared settings document.
  2. Long transactions, which hold their documents longer and collide more often: slow work, an external API call or user input in the middle of one.
  3. A hot document that every transaction touches, such as a global sequence or totals document.
  4. Ordinary writes to documents a transaction is about to change: a background job updating documents while transactions read and then write them.
  5. Hand-written transactions without a retry loop, using startTransaction() and commitTransaction() directly. The conflict is normal; the missing retry is the bug.

How to fix it

Retry the whole transaction

The drivers’ callback API retries for you. In Node.js, withTransaction reruns the callback when the error has the TransientTransactionError label, and retries the commit when it’s unknown whether it succeeded:

const session = client.startSession()
try {
  await session.withTransaction(async () => {
    await accounts.updateOne({ _id: "alice" }, { $inc: { balance: -10 } }, { session })
    await accounts.updateOne({ _id: "bob" }, { $inc: { balance: 10 } }, { session })
  })
} finally {
  await session.endSession()
}

The callback may run more than once, so keep side effects (emails, HTTP calls) outside it. If you manage transactions yourself, catch the error, check err.hasErrorLabel("TransientTransactionError"), abort and start again from the beginning.

Keep transactions short

Do slow work (API calls, computing, waiting for input) before the transaction starts, and keep inside it only the reads and writes that must happen together. The shorter it is, the smaller the window for a conflict.

Spread out hot documents

Split a single counter into several (one per worker, or one per hour) and add them up when you read, or record events as new documents instead of updating one.

Use a single-document write when it’s enough

One update to one document is atomic without a transaction. $inc: { stock: -1 } with a filter of { stock: { $gte: 1 } } decrements safely under concurrency, and writes outside transactions wait instead of failing.

Reproduce it

A temporary single-member replica set of our own (mongo:8.0 --replSet rs0, MongoDB 8.0.32, removed afterwards), since transactions need one. Two sessions in mongosh 2.12.0:

const s1 = db.getMongo().startSession()
const s2 = db.getMongo().startSession()
const a1 = s1.getDatabase("seo_err_mongo").accounts
const a2 = s2.getDatabase("seo_err_mongo").accounts
s1.startTransaction()
a1.updateOne({ _id: "alice" }, { $inc: { balance: -10 } })
s2.startTransaction()
a2.updateOne({ _id: "alice" }, { $inc: { balance: -20 } })
MongoServerError[WriteConflict]: Caused by :: Write conflict during plan execution and yielding is disabled. :: Please retry your operation or multi-document transaction.

The error’s code was 112 and its errorLabels [ 'TransientTransactionError' ]. Repeating the write in the same session gave code 251, NoSuchTransaction. After s1 committed, Alice had 90: only the first transaction’s change was kept.

A plain updateOne on the same document from another connection, while the first transaction was still open, didn’t conflict: it waited, and with { maxTimeMS: 2000 } it failed after 2 seconds with operation exceeded time limit. The other order did conflict: a transaction read Bob’s document, a plain update outside it added 100 to his balance, and the transaction’s own update of Bob then failed with the same code 112 and label.

With the Node.js driver 6.20.0, two withTransaction calls changed the same document, the first holding its transaction for half a second. The second callback ran 83 times, retried by the driver, and succeeded once the first committed; both increments were kept.

In Inlet

Inlet runs MongoDB queries in mongosh syntax, so you can look at the documents your transactions wrote, as tables and in the inspector. Edits made in Inlet are checked against what you loaded: if someone changed the document meanwhile, nothing is saved and Inlet shows their version beside yours.

Inlet: a database client for the Mac

One native app for PostgreSQL, MySQL, SQL Server, SQLite, MongoDB and Redis. It explains errors where they happen, holds your edits until you save them, and keeps production read-only until you say so.

Version 0.1.0 · macOS 26 Tahoe or later · Apple silicon and Intel