t8y2/dbx · error · java.lang.IllegalArgumentException
Bulk update requires update operators such as $set
Error message
Bulk update requires update operators such as $set
What it means
MongoAgent deliberately restricts bulk updateOne/updateMany to operator documents (updates containing keys like $set, $unset, $inc, $push). A plain replacement document would silently replace every matched document, so requireBulkUpdateOperatorDocument throws this IllegalArgumentException to prevent accidental mass replacement; replacements belong on the single-document save path.
Source
Thrown at agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java:1682
}
static boolean isUpdateOperatorDocument(Document doc) {
if (doc.isEmpty()) {
return false;
}
for (String key : doc.keySet()) {
if (!key.startsWith("$")) {
return false;
}
}
return true;
}
static void requireBulkUpdateOperatorDocument(Document doc) {
if (!isUpdateOperatorDocument(doc)) {
// updateOne/updateMany are shell-style bulk updates here; replacements stay on the
// single-document save path so a broad filter cannot replace many documents by accident.
throw new IllegalArgumentException("Bulk update requires update operators such as $set");
}
}
private static Object deleteDocument(JsonObject params) {
MongoClient c = requireClient();
String database = params.get("database").getAsString();
String collection = params.get("collection").getAsString();
String id = params.get("id").getAsString();
var col = c.getDatabase(database).getCollection(collection);
var result = col.deleteOne(new Document("_id", parseId(id)));
return Collections.singletonMap("deleted_count", result.getDeletedCount());
}
private static Object deleteDocuments(JsonObject params) {
MongoClient c = requireClient();
String database = params.get("database").getAsString();
String collection = params.get("collection").getAsString();View on GitHub (pinned to c0390bff16)
Solutions
- Wrap the fields in $set: `{"$set": {"status": "archived", "note": "batch"}}`.
- Use the appropriate operator ($inc, $push, $addToSet, $unset) for the intended mutation.
- If a true replacement is intended, replace only one document at a time via the save/replace path or a unique _id filter.
- Add a pre-send check that at least one key starts with `$` when targeting updateOne/updateMany.
Example fix
// before
{"updateMany": {"filter": {"stale": true}, "update": {"archived": true}}}
// after
{"updateMany": {"filter": {"stale": true}, "update": {"$set": {"archived": true}}}} Defensive patterns
Strategy: validation
Validate before calling
// Java: bulk updates must contain at least one $ operator
Document update = /* parsed update document */;
boolean hasOperator = update.keySet().stream().anyMatch(k -> k.startsWith("$"));
if (!hasOperator) {
update = new Document("$set", update);
} Type guard
static boolean isUpdateOperatorDocument(Document doc) { return doc != null && doc.keySet().stream().anyMatch(k -> k.startsWith("$")); } Try / catch
try { agent.updateMany(filter, updateDoc); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("Bulk update requires update operators")) {
// wrap fields in $set and retry, or route to single-doc replace path
} else throw e;
} Prevention
- Always use $set/$unset/$inc in updateOne/updateMany payloads
- Reserve whole-document replacement for the single-document save/replace path
- Add a pre-send assertion that bulk update docs start with a $ operator
When it happens
Trigger: Calling updateMany with `"update": {"status": "archived", "note": "batch"}` (no $ operators) matching many documents; the same shape works on the single-doc save path, so users copy it to the bulk path.
Common situations: Migrating from update-with-replacement habits (SQL UPDATE-style field maps); refactors that drop the $set wrapper; copy-pasting a replaceOne document into updateMany.
Related errors
- MongoDB aggregate option ${key} must be a non-negative integ
- MongoDB explain verbosity must be queryPlanner, executionSta
- Unsupported findOne option: ${key}
- Unsupported collation option: ${key}
- Invalid collation: locale must not be empty
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/d1be20aa89587230.
Report an issue: GitHub.