Skip to content
MongoDB

MongoDB Error 112

WriteConflict: please retry your operation or multi-document transaction

Applies to: MongoDB 5.0 to 8.0 (wording changed in 7.0; checked against the r6.0.0, r7.0.0 and r8.0.0 source)
Last technically reviewed 24 October 2026 on MongoDB 8.0 documentation and source (error_codes.yml r8.0.0); not run locally
The full message
MongoServerError: Caused by :: Write conflict during plan execution and yielding is disabled. :: Please retry your operation or multi-document transaction.
Other forms of this message
MongoDB 5.0 and 6.0 wording
WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.
Error labels returned with it inside a transaction
errorLabels: [ 'TransientTransactionError' ], code: 112, codeName: 'WriteConflict'
Error code
112
Code name
WriteConflict
Product
MongoDB
Versions
MongoDB 5.0 to 8.0 (wording changed in 7.0; checked against the r6.0.0, r7.0.0 and r8.0.0 source)
Last reviewed
24 October 2026

What it means

Error 112 (WriteConflict) means two operations tried to change the same document at the same time and this one lost; inside a transaction the whole transaction is aborted and must be retried.

MongoDB's storage engine lets only one uncommitted change to a document exist at a time. When a second operation tries to modify a document that another operation has already changed and not yet committed, the second one gets a write conflict. For a single write outside a transaction the server normally retries this internally (MongoDB 8.0's writeConflictRetry helper), so applications rarely see it. Inside a multi-document transaction it cannot retry for you: the transaction is aborted and the error is returned. MongoDB documents the case directly: if a write outside the transaction changes a document that the transaction later tries to modify, the transaction aborts because of a write conflict.

Because it is a transaction failure with no lasting effect, the server attaches the TransientTransactionError label (error_labels.cpp in the 8.0 source lists WriteConflict as transient). That label is the signal to rerun the whole transaction from the start, not just the failing statement. The callback API (withTransaction) in mongosh and the drivers does this automatically; the core API (startTransaction and commitTransaction) leaves it to you. Since MongoDB 7.0 the message has the form Caused by :: <context> :: Please retry..., where the context names the internal place the conflict was detected.

MongoDB also documents a cache case: an uncommitted transaction that puts too much pressure on the WiredTiger cache is aborted with a write conflict error. From 6.2 a transaction that can never fit returns TransactionTooLargeForCache instead; earlier versions returned TemporarilyUnavailable or WriteConflict.

Common causes

  • Two transactions update the same document (a counter, a stock level, an account balance) at the same moment.
  • A transaction reads a document and later updates it after a write outside the transaction has already changed it.
  • A long transaction keeps documents modified but uncommitted for a long time, so other writers keep colliding with it.
  • One "hot" document is updated by almost every request (a global counter or a status document).
  • A large or long transaction puts pressure on the WiredTiger cache and is aborted with a write conflict.

Diagnose it

Read-only These mongosh commands only read data, indexes, statistics and server state (find, aggregate without $out or $merge, getIndexes, stats, currentOp, rs.status). They do not change data, users or settings, so they are safe to run first.

List open transactions and how long they have been open

db.getSiblingDB("admin").aggregate([
  { $currentOp: { allUsers: true, idleSessions: true } },
  { $match: { transaction: { $exists: true } } },
  { $project: { lsid: 1, active: 1, ns: 1,
      "transaction.parameters.txnNumber": 1,
      "transaction.timeOpenMicros": 1,
      "transaction.timeInactiveMicros": 1 } }
])
What to look for

One document per open transaction. Large timeOpenMicros values, or transactions that sit inactive for long periods, show the long-running transactions that other writers collide with.

Count write conflicts and aborted transactions

const s = db.serverStatus()
printjson({
  writeConflicts: s.metrics.operation.writeConflicts,
  transactions: s.transactions
})
What to look for

metrics.operation.writeConflicts (operations that met a write conflict) and the transactions section (totalStarted, totalAborted, totalCommitted, currentOpen). Compare two readings a minute apart to see the rate; a high abort ratio means retries are frequent.

Find the operations that hit conflicts (when the profiler is on)

db.system.profile.find(
  { writeConflicts: { $gt: 0 } },
  { op: 1, ns: 1, command: 1, writeConflicts: 1, millis: 1, ts: 1 }
).sort({ ts: -1 }).limit(20)
What to look for

Profiled operations with their writeConflicts count, which shows the collection and the filter of the hot document.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Use the callback API so the transaction is retried

Client or network side

withTransaction reruns the callback when an error carries TransientTransactionError and retries the commit on UnknownTransactionCommitResult. Keep the callback free of side effects outside the database (emails, HTTP calls), because it may run more than once.

const session = db.getMongo().startSession()
try {
  session.withTransaction(() => {
    const shop = session.getDatabase("shop")
    shop.stock.updateOne({ sku: "PEN-1", qty: { $gte: 1 } }, { $inc: { qty: -1 } })
    shop.orders.insertOne({ sku: "PEN-1", qty: 1, at: new Date() })
  })
} finally {
  session.endSession()
}

Retry on the error label with the core API

Client or network side

If you manage transactions yourself, abort and rerun the whole transaction when the error has the TransientTransactionError label. Check the label, not the code, and cap the number of attempts with a short backoff.

function runTxn(session, work, attempts = 5) {
  for (let i = 1; ; i++) {
    session.startTransaction()
    try {
      work(session)
      session.commitTransaction()
      return
    } catch (e) {
      try { session.abortTransaction() } catch (ignored) {}
      const transient = (e.errorLabels || []).includes("TransientTransactionError")
      if (!transient || i >= attempts) throw e
      sleep(50 * i)
    }
  }
}

Make transactions short and touch hot documents last

Client or network side

Do reads, validation and calculations before starting the transaction, keep only the writes inside it, and update the most contended document as late as possible so it is held uncommitted for the shortest time.

Avoid a single hot document

Changes schema

When one document is updated by every request, spread the writes: keep several counter documents and sum them on read, or record events and aggregate them later. A single atomic update outside a transaction ($inc on one document) also avoids the transaction abort, because the server retries that write itself.

// one of N counter shards, chosen at random per write
db.counters.updateOne(
  { _id: { name: "page_views", shard: Math.floor(Math.random() * 8) } },
  { $inc: { n: 1 } },
  { upsert: true }
)

Examples

Two transactions decrement the same stock document

Not reproduced here: no MongoDB server is installed for this site. The wording is built by MongoDB 8.0's source (exception_util.h, throwWriteConflictException, with the context string from plan_executor_impl.cpp, used when an operation cannot yield, as inside a transaction). The exact context text depends on where the conflict is detected, and the server also returns the TransientTransactionError label.

// session A
sA.startTransaction()
sA.getDatabase("shop").stock.updateOne({ sku: "PEN-1" }, { $inc: { qty: -1 } })

// session B, before A commits
sB.startTransaction()
sB.getDatabase("shop").stock.updateOne({ sku: "PEN-1" }, { $inc: { qty: -1 } })
Expected result (documented format, not run)
MongoServerError: Caused by :: Write conflict during plan execution and yielding is disabled. :: Please retry your operation or multi-document transaction.

The same conflict on MongoDB 6.0

Not reproduced here: no MongoDB server is installed for this site. This is the fixed text of WriteConflictException in the MongoDB 5.0 and 6.0 source (write_conflict_exception.cpp at r5.0.0 and r6.0.0); MongoDB 7.0 and 8.0 use the "Caused by ::" form instead.

// same two sessions as above, on a MongoDB 6.0 replica set
Expected result (documented format, not run)
MongoServerError: WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.

How to prevent it

Write every transaction through withTransaction (or an equivalent wrapper that retries on TransientTransactionError), keep transactions short, and design data so that concurrent requests rarely update the same document.

Track metrics.operation.writeConflicts and transactions.totalAborted over time; a rising rate is an early sign of a hot document or of transactions that stay open too long.

Common questions

How do I fix WriteConflict error 112 in MongoDB?

Retry the whole transaction when the error carries the TransientTransactionError label (withTransaction does it for you), then reduce how often it happens: shorter transactions, fewer updates to the same hot document.

Why do I get WriteConflict only inside transactions?

For a single write outside a transaction the server retries the conflict internally until it succeeds. Inside a multi-document transaction it cannot, so it aborts the transaction and returns error 112 for the application to retry.

Is retrying a write conflict safe?

Yes for the database work: the aborted transaction left no changes. Rerun the whole transaction, not only the failed statement, and keep non-database side effects outside the retried code.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on MongoDB 8.0 documentation and source (error_codes.yml r8.0.0); not run locally. Codes and code names are checked against MongoDB's error_codes.yml (8.0); no MongoDB server was available, so the examples were not run locally.

Still stuck on a MongoDB error?

Browse the full MongoDB error library, or get hands-on help from an experienced SQL professional.