t8y2/dbx · error · java.lang.IllegalArgumentException
Index options cannot contain "key"; specify index fields in
Error message
Index options cannot contain "key"; specify index fields in keys JSON
What it means
In createIndex, index fields must be given via keys_json; the options_json document is merged into the index spec, so an option named "key" would collide with the required "key" field and corrupt the specification. The agent therefore rejects options containing a "key" entry with IllegalArgumentException. This is a schema conflict guard, not a MongoDB server rule.
Source
Thrown at agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java:1010
// Without an explicit old version, preserve MongoDB's single-command array semantics.
return false;
}
}
private static Object createIndex(JsonObject params) {
MongoClient c = requireClient();
String database = params.get("database").getAsString();
String collection = params.get("collection").getAsString();
Document keys = requiredDocument(params, "keys_json", "Index keys");
if (keys.isEmpty()) {
throw new IllegalArgumentException("Index keys are required");
}
Document index = new Document("key", keys);
Document options = documentOrNull(params, "options_json");
if (options != null) {
if (options.containsKey("key")) {
throw new IllegalArgumentException("Index options cannot contain \"key\"; specify index fields in keys JSON");
}
index.putAll(options);
}
String name;
if (!index.containsKey("name")) {
name = defaultIndexName(keys);
index.put("name", name);
} else if (!(index.get("name") instanceof String)) {
throw new IllegalArgumentException("Index option \"name\" must be a non-empty string");
} else {
name = (String) index.get("name");
if (name.isBlank()) {
throw new IllegalArgumentException("Index option \"name\" must be a non-empty string");
}
}
c.getDatabase(database).runCommand(
new Document("createIndexes", collection)View on GitHub (pinned to c0390bff16)
Solutions
- Move the key fields out of options_json into keys_json, keeping only true options (unique, name, expireAfterSeconds, etc.) in options_json.
- If you have a full index spec, split it: "key" goes to keys_json, everything else to options_json.
- Validate the options map before sending to ensure it has no "key" entry.
Example fix
// before
{"keys_json": {}, "options_json": {"key": {"email": 1}, "unique": true}}
// after
{"keys_json": {"email": 1}, "options_json": {"unique": true}} Defensive patterns
Strategy: validation
Validate before calling
if (params.options_json && "key" in params.options_json) {
// move it: params.keys_json = params.options_json.key; delete params.options_json.key;
throw new Error("Move index fields from options_json.key into keys_json");
} Type guard
function optionsHaveNoKey(options) {
return options == null || !("key" in options);
} Try / catch
try {
await agent.createIndex({ database, collection, keys_json: keys, options_json: options });
} catch (e) {
if (String(e.message).includes('cannot contain "key"')) {
const { key, ...rest } = options; // split and retry
await agent.createIndex({ database, collection, keys_json: key, options_json: rest });
} else throw e;
} Prevention
- Never merge a raw index spec (from getIndexes) into options_json; split key out first.
- Keep index fields only in keys_json and true options (unique, name, expireAfterSeconds) in options_json.
- Add a pre-send check that options_json has no "key" property.
When it happens
Trigger: Calling createIndex with options_json that includes a "key" field, e.g. {"options_json": {"key": {"field": 1}, "unique": true}}.
Common situations: Confusing keys and options — putting index fields into options_json instead of keys_json; merging a full index spec (as returned by getIndexes) into options; copy-paste from server-side index documents.
Related errors
- Index keys are required
- Index option "name" must be a non-empty string
- MongoDB Legacy aggregate option hint must be an object
- MongoDB aggregate option ${key} must be a non-negative integ
- MongoDB explain verbosity must be queryPlanner, executionSta
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/500062dd816b8147.
Report an issue: GitHub.