Get Started Free

Fix "E11000 duplicate key error collection" in MongoDB

What MongoDB's E11000 duplicate key error means, how to read the index and dup key in the message, and how to fix it for _id, null values and upserts.

Updated October 24, 2026 ยท Tested on MongoDB 7.0.45, Node.js driver 6.12, PyMongo 4.19

Quick Answer

A unique index already has a document with that value. The message tells you exactly which index and which value:

MongoServerError: E11000 duplicate key error collection: shop.users index: email_1 dup key: { email: "a@x.io" }

Here, the unique index email_1 already contains "a@x.io". Either the insert is a real duplicate (update the existing document instead, usually with an upsert), or the index is stricter than you meant it to be.

Read the error message

Every E11000 message has the same three parts, and together they point straight at the problem:

PartExampleWhat it tells you
collectionshop.usersDatabase and collection, as db.collection
indexemail_1The unique index that rejected the write. Run db.users.getIndexes() to see its definition
dup key{ email: "a@x.io" }The value that already exists

Then find the document that already holds the value:

db.users.find({ email: 'a@x.io' })

The error code is 11000. Drivers expose it as err.code === 11000 in Node.js and as DuplicateKeyError in PyMongo.

What causes it

dup key looks likeCauseFix
{ _id: 5 }You set _id yourself and reused a valueLet MongoDB generate _id, or update instead of insert
{ email: "a@x.io" }A real duplicate, often a retried request or a double-submitted formUpsert, or catch code 11000 and treat it as "already exists"
{ email: null }Two documents without the field, under a unique indexUse a partial index
{ username: "x" } on an index you don't expectA leftover index from an old schema or an ORMDrop the stale index

What we found testing this

You don't have to parse the message string. Every client we tried exposes the index and the duplicate value as structured fields:

ClientError classIndex fieldsDuplicate value
Node.js driver 6MongoServerErrorerr.keyPatternerr.keyValue
Node.js, insertManyMongoBulkWriteErrorerr.writeErrors[i]err.insertedCount = rows that got in
PyMongo 4.19DuplicateKeyErrore.details['keyPattern']e.details['keyValue']
PyMongo, insert_manyBulkWriteErrore.details['writeErrors']e.details['nInserted']
  • A case-insensitive unique index hides the value. On an index created with collation: { locale: 'en', strength: 2 }, inserting A@x.io next to a@x.io failed with dup key: { email: "CollationKey(0x290a7a57083945010a)" }: a binary sort key, not the email. Use keyValue from the driver or look the document up with the same collation. (Without a collation, A@x.io and a@x.io were both accepted: unique indexes are case-sensitive by default.)
  • sparse and $exists: true don't fix duplicate nulls. Both allowed any number of documents without the field, but the second document with an explicit email: null still failed with dup key: { email: null }, because the field exists. Only partialFilterExpression: { email: { $type: 'string' } } accepted repeated nulls, which is why the fix below uses $type.
  • How many rows got in depends on ordered. Inserting [1, 2, 1, 3, 4] into a unique field stored 2 documents with the default ordered insert (it stopped at the first duplicate), and inserting [1, 2, 1, 3, 1] with ordered: false stored 3 and reported 2 write errors.

Cause 1: inserting something that already exists

If the intent is "create it, or update it if it's there", don't insert. Upsert:

db.users.updateOne(
  { email: 'a@x.io' },                  // match on the unique field
  { $set: { name: 'Ana', lastSeen: new Date() } },
  { upsert: true }
)

When a duplicate is expected and harmless, catch it instead:

try {
  await db.collection('users').insertOne({ email })
} catch (err) {
  if (err.code === 11000) return { alreadyRegistered: true }
  throw err
}
from pymongo.errors import DuplicateKeyError

try:
    db.users.insert_one({"email": email})
except DuplicateKeyError:
    pass  # already registered

Two upserts racing on the same new value can still raise E11000, because both see "no match" and both try to insert. Retry the upsert once on code 11000 and the second attempt will find the document.

Cause 2: dup key { field: null }

A unique index treats a missing field as null, so it allows exactly one document without the field. The second one fails:

db.users.insertMany([{ name: 'no email 1' }, { name: 'no email 2' }])
// E11000 duplicate key error collection: shop.users index: email_1 dup key: { email: null }

If the field is optional, make the index cover only documents that have it, with a partial index:

db.users.dropIndex('email_1')
db.users.createIndex(
  { email: 1 },
  { unique: true, partialFilterExpression: { email: { $type: 'string' } } }
)

Now any number of documents can omit email, but two documents can't share the same address.

Cause 3: creating a unique index on data with duplicates

createIndex({ email: 1 }, { unique: true }) fails with the same E11000 if duplicates already exist, prefixed with Index build failed. Find them first:

db.users.aggregate([
  { $group: { _id: '$email', count: { $sum: 1 }, ids: { $push: '$_id' } } },
  { $match: { count: { $gt: 1 } } }
])

Decide which copy to keep, delete or merge the others, then build the index.

Cause 4: bulk inserts and stale indexes

insertMany stops at the first duplicate by default, so the documents after it are never written. Pass ordered: false to insert everything that can be inserted and get one error listing the duplicates:

db.users.insertMany(docs, { ordered: false })   // MongoBulkWriteError, but non-duplicates are saved

If the index named in the error doesn't match your current schema, it's probably left over from an earlier version of the app, or created by an ORM such as Mongoose (unique: true in a schema creates an index). List and drop it:

db.users.getIndexes()
db.users.dropIndex('username_1')

Frequently Asked Questions

What is error code 11000 in MongoDB?

It is the duplicate key error. A write tried to store a value that already exists in a unique index, including the default unique index on _id.

Why do I get E11000 with dup key null?

A unique index counts a missing field as null, so only one document can lack it. Use a partial index with partialFilterExpression to index only documents that have the field.

Does Mongoose unique: true validate uniqueness?

No. It only creates a unique index in MongoDB. The database rejects the duplicate with E11000, which Mongoose passes back as an error with code 11000.

How do I insert many documents and skip duplicates?

Use insertMany with ordered: false. Non-duplicate documents are inserted, and the error lists the ones that were rejected.

VisuaLeaf

See every unique index before it bites

VisuaLeaf's index manager lists every index on a collection with its options, size and usage, and lets you build unique and partial indexes without remembering the syntax.