t8y2/dbx · error · IllegalArgumentException
MongoDB aggregate option cursor must be an object
Error message
MongoDB aggregate option cursor must be an object
What it means
The 'cursor' aggregate option must be a Document (object) because the library iterates its keys to extract batchSize for the driver's iterable.batchSize(). If the value is a scalar (string, number, boolean) the instanceof Document check fails and IllegalArgumentException is thrown before any query runs.
Source
Thrown at agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java:576
}
if (!aggregateExplain(options) && !command.containsKey("cursor")) {
command.append("cursor", new Document());
}
return command;
}
private static AggregateIterable<Document> applyAggregateOptions(
AggregateIterable<Document> iterable,
Document options
) {
validateAggregateOptions(options);
if (options.containsKey("allowDiskUse")) {
iterable = iterable.allowDiskUse(aggregateBoolean(options, "allowDiskUse"));
}
if (options.containsKey("cursor")) {
Object rawCursor = options.get("cursor");
if (!(rawCursor instanceof Document cursor)) {
throw new IllegalArgumentException("MongoDB aggregate option cursor must be an object");
}
for (String key : cursor.keySet()) {
if (!"batchSize".equals(key)) {
throw new IllegalArgumentException("Unsupported MongoDB aggregate cursor option: " + key);
}
}
if (cursor.containsKey("batchSize")) {
iterable = iterable.batchSize(aggregateNonNegativeInt(cursor, "batchSize"));
}
}
if (options.containsKey("maxTimeMS")) {
iterable = iterable.maxTime(aggregateNonNegativeLong(options, "maxTimeMS"), TimeUnit.MILLISECONDS);
}
if (options.containsKey("maxAwaitTimeMS")) {
iterable = iterable.maxAwaitTime(
aggregateNonNegativeLong(options, "maxAwaitTimeMS"),
TimeUnit.MILLISECONDS
);View on GitHub (pinned to c0390bff16)
Solutions
- Pass cursor as an object: new Document("batchSize", 100) or JSON {"cursor": {"batchSize": 100}}.
- If you have a stringified JSON, parse it into a Document/BsonDocument before putting it in options.
- If you only wanted a batch size, set it inside the cursor object: {"cursor":{"batchSize":N}}.
- Drop the cursor option if default cursor behavior is acceptable.
Example fix
// before
Document options = new Document("cursor", "{\"batchSize\": 100}");
// after
Document options = new Document("cursor", new Document("batchSize", 100)); Defensive patterns
Strategy: validation
Validate before calling
Object cursor = options.get("cursor");
if (cursor != null && !(cursor instanceof Document)) {
throw new IllegalArgumentException("cursor must be an object like {batchSize:N}");
} Type guard
static boolean isDocument(Object v) {
return v == null || v instanceof Document;
} Try / catch
try {
agent.aggregate(db, collection, pipeline, options);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("cursor must be an object")) {
Object raw = options.get("cursor");
options.put("cursor", Document.parse(String.valueOf(raw)));
// retry
} else throw e;
} Prevention
- Always pass cursor as {"batchSize": N}, never a string or bare number
- Parse stringified JSON cursor configs before use
- Keep cursor options minimal — only batchSize is supported
- Unit-test option payloads built from external config
When it happens
Trigger: Calling aggregate with options such as {"cursor": true}, {"cursor": "{}"} (stringified JSON), or {"cursor": 100} instead of a nested object.
Common situations: Passing cursor as a JSON string copied from a mongo shell example without parsing; confusing batchSize (a number inside cursor) with the cursor option itself; older code that sent cursor:{batchSize:N} as an encoded string through an HTTP/MCP payload.
Related errors
- MongoDB aggregate option explain must be a boolean
- MongoDB aggregate option collation must be an object
- MongoDB aggregate option comment must be a string
- MongoDB Legacy aggregate option hint must be an object
- Unsupported MongoDB aggregate cursor option: ${key}
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/ca4ff1b5d250de46.
Report an issue: GitHub.