MongoServerError: E11000 duplicate key error collection: app.users index: email_1 dup key: { email: "ada@example.com" }

Node.js · updated 2026-11-04

Thrown by insertOne, insertMany, updateOne with upsert, and Mongoose save() when a document would repeat a value in a unique index. The message includes the collection, the index name and the duplicate key value.

MongoServerError: E11000 duplicate key error collection: app.users index: email_1 dup key: { email: "ada@example.com" }
    at InsertOneOperation.execute (/app/node_modules/mongodb/lib/operations/insert.js:51:19)
    at async createUser (file:///app/src/users.js:18:3) {
  errorResponse: { index: 0, code: 11000, keyPattern: { email: 1 }, keyValue: { email: 'ada@example.com' } },
  code: 11000
}

Quick fix

Read keyPattern and keyValue on the error to see which field collided. For signups, catch code 11000 and return a 409. For create-or-update logic, use updateOne(filter, { $set }, { upsert: true }) or findOneAndUpdate with upsert so MongoDB decides atomically.

  1. Check err.keyPattern and err.keyValue for the field and value.
  2. Catch err.code === 11000 and answer with a clear 409 instead of a 500.
  3. Replace "find, then insert" with an upsert so concurrent requests cannot both insert.
  4. Normalize values before saving (lowercase emails) so near-duplicates are caught consistently.
  5. If the error names an index you did not expect (for example on a field that is often null), check the index definition: a unique index treats missing values as null and allows only one.
typescript
import { MongoServerError } from 'mongodb';

try {
  await users.insertOne({ email: email.trim().toLowerCase(), name });
} catch (err) {
  if (err instanceof MongoServerError && err.code === 11000) {
    throw new HttpError(409, 'An account with this email already exists');
  }
  throw err;
}

// Create-or-update without a race
await subscriptions.updateOne({ stripeId }, { $set: { status } }, { upsert: true });

Why it happens

Double submits and retries

Repeated form posts, client retries and duplicate webhooks insert the same document twice.

Check-then-insert races

findOne followed by insertOne lets two concurrent requests both see nothing and both insert.

A unique index on a sometimes-missing field

Documents without the field are indexed as null, so a second document missing it collides. A partial or sparse index fixes that.

A leftover index

An index created long ago (or by a Mongoose schema) on a field that is no longer unique keeps rejecting writes until it is dropped.

Other fixes

  • Use partialFilterExpression on unique indexes for optional fields.
  • insertMany with ordered: false keeps inserting the rest of a batch and reports duplicates at the end.

Same error, other wording

  • MongoServerError: E11000 duplicate key error collection: app.orders index: _id_ dup key: { _id: ObjectId(...) }
  • MongoBulkWriteError: E11000 duplicate key error collection
  • E11000 duplicate key error index: email_1 dup key: { email: null }

Let your coding agent catch the next one

Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:

> Find the MongoDB E11000 duplicate key errors in production, group them by collection and index, tell me which are retries or races, and switch those writes to upserts or a handled 409.

Plans from $29/moSee what your agent readsSee the setupCancel any time from the billing portal

Related errors

References: MongoDB docs: unique indexes, MongoDB docs: partial indexes