What it means
An index is identified two ways: by its keys ({ email: 1 }) and by its name (email_1 unless you
chose one). createIndex succeeds without doing anything when the same index already exists, and
fails when the request only partly matches an existing one:
| Message | Code | What clashes |
|---|---|---|
Index already exists with a different name: email_idx | 85 IndexOptionsConflict | The same keys and options exist under another name |
An equivalent index already exists with the same name but different options | 85 | Same name and keys, different options (such as expireAfterSeconds) |
An equivalent index already exists with a different name and options | 85 | A second text index (a collection can have one) |
An existing index has the same name as the requested index … | 86 IndexKeySpecsConflict | Same name, different keys or unique/sparse |
The 86 message goes on to print both definitions (Requested index: { … }, existing index: { … }),
which shows the difference. Older servers worded the second case Index with name: … already exists with different options (code 85 as well).
Nothing is changed: the existing index stays as it is.
Common causes
- Making an index unique after the fact.
{ email: 1 }exists, and the schema now saysunique: true. The default name is the same (email_1), the options aren’t: code 86. - The same index created under two names: once by hand as
email_idx, then by code with the default name. - Changing a TTL index’s
expireAfterSecondsby callingcreateIndexagain with the new value. - ODM start-up index builds. Mongoose’s
autoIndex(and other libraries’ equivalents) callcreateIndexfor every index in the schema when the app starts, so a schema change shows up as this error in the logs, or fromModel.init(). - A second text index, to search more fields.
How to fix it
Compare what exists with what you asked for
db.users.getIndexes()
Find the index with the same keys or the same name, and see which option differs.
Drop it and create the one you want
db.users.dropIndex("email_1")
db.users.createIndex({ email: 1 }, { unique: true })
Between the two, queries can’t use that index. On a busy collection, create the new one first under
another name, then drop the old one: two indexes may share keys when they differ in unique (as
the reproduction below shows), but not when they differ only in name. A unique index fails to build
if the data already has duplicates; see E11000 duplicate key.
Change a TTL without rebuilding
db.runCommand({
collMod: "sessions",
index: { keyPattern: { createdAt: 1 }, expireAfterSeconds: 86400 }
})
Keep the name you already use
If an index with the right keys and options exists under another name, use it: drop the duplicate
request from your code, or pass that name ({ name: "email_idx" }) so the request matches.
In Mongoose, sync the indexes
Model.diffIndexes() lists what would be dropped and created, and Model.syncIndexes() drops the
indexes that aren’t in the schema and builds the ones that are missing. Run it from a deployment
script rather than on every start, and with autoIndex: false in production so start-up doesn’t
build indexes.
Replace the text index
A collection has one text index. Drop it and create one covering every field you want to search.
Reproduce it
MongoDB 8.0.32, mongosh 2.12.0. An index email_idx on { email: 1 }, then the same keys with the
default name:
db.users.createIndex({ email: 1 }, { name: "email_idx" })
db.users.createIndex({ email: 1 })
MongoServerError[IndexOptionsConflict]: Index already exists with a different name: email_idx
An index name_1 on { name: 1 }, then the same keys with unique: true:
MongoServerError[IndexKeySpecsConflict]: An existing index has the same name as the requested index. When index names are not specified, they are auto generated and can cause conflicts. Please refer to our documentation. Requested index: { v: 2, unique: true, key: { name: 1 }, name: "name_1" }, existing index: { v: 2, key: { name: 1 }, name: "name_1" }
sparse: true, and { name: -1 } with name: "name_1", gave the same code 86. A TTL index with
expireAfterSeconds: 3600, requested again with 60:
MongoServerError[IndexOptionsConflict]: An equivalent index already exists with the same name but different options. Requested index: { v: 2, key: { created: 1 }, name: "created_1", expireAfterSeconds: 60 }, existing index: { v: 2, key: { created: 1 }, name: "created_1", expireAfterSeconds: 3600 }
collMod changed another TTL index from 3600 to 86400 seconds and replied with
expireAfterSeconds_old and expireAfterSeconds_new. Meanwhile createIndex({ email: 1 }, { unique: true }) succeeded beside email_idx, as a second index named email_1.
With Mongoose 8.23.0, a schema declaring email as unique on a collection with a plain email_1
index: the model’s index event and Model.init() both reported the code 86 error.
Model.diffIndexes() returned { toDrop: ["email_1"], toCreate: [{ email: 1 }] }, and
Model.syncIndexes() dropped the old index and built the unique one.
In Inlet
Queries use mongosh syntax, so db.users.getIndexes(), dropIndex and createIndex run in a query
tab, and a refused createIndex shows the server’s message with both definitions.