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.
- Check err.keyPattern and err.keyValue for the field and value.
- Catch err.code === 11000 and answer with a clear 409 instead of a 500.
- Replace "find, then insert" with an upsert so concurrent requests cannot both insert.
- Normalize values before saving (lowercase emails) so near-duplicates are caught consistently.
- 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.
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.
Related errors
- PrismaClientKnownRequestError: Unique constraint failed on the fields: (`email`)
- psycopg.errors.UniqueViolation: duplicate key value violates unique constraint...
- [UnhandledPromiseRejection: This error originated either by throwing inside of an async...
References: MongoDB docs: unique indexes, MongoDB docs: partial indexes