{"record":{"id":"2374b95dffb684c6","repo":"t8y2/dbx","slug":"unsupported-mongodb-aggregate-cursor-option-key","errorCode":null,"errorMessage":"Unsupported MongoDB aggregate cursor option: ${key}","messagePattern":"Unsupported MongoDB aggregate cursor option: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java","lineNumber":580,"sourceCode":"        return command;\n    }\n\n    private static AggregateIterable<Document> applyAggregateOptions(\n        AggregateIterable<Document> iterable,\n        Document options\n    ) {\n        validateAggregateOptions(options);\n        if (options.containsKey(\"allowDiskUse\")) {\n            iterable = iterable.allowDiskUse(aggregateBoolean(options, \"allowDiskUse\"));\n        }\n        if (options.containsKey(\"cursor\")) {\n            Object rawCursor = options.get(\"cursor\");\n            if (!(rawCursor instanceof Document cursor)) {\n                throw new IllegalArgumentException(\"MongoDB aggregate option cursor must be an object\");\n            }\n            for (String key : cursor.keySet()) {\n                if (!\"batchSize\".equals(key)) {\n                    throw new IllegalArgumentException(\"Unsupported MongoDB aggregate cursor option: \" + key);\n                }\n            }\n            if (cursor.containsKey(\"batchSize\")) {\n                iterable = iterable.batchSize(aggregateNonNegativeInt(cursor, \"batchSize\"));\n            }\n        }\n        if (options.containsKey(\"maxTimeMS\")) {\n            iterable = iterable.maxTime(aggregateNonNegativeLong(options, \"maxTimeMS\"), TimeUnit.MILLISECONDS);\n        }\n        if (options.containsKey(\"maxAwaitTimeMS\")) {\n            iterable = iterable.maxAwaitTime(\n                aggregateNonNegativeLong(options, \"maxAwaitTimeMS\"),\n                TimeUnit.MILLISECONDS\n            );\n        }\n        if (options.containsKey(\"bypassDocumentValidation\")) {\n            iterable = iterable.bypassDocumentValidation(aggregateBoolean(options, \"bypassDocumentValidation\"));\n        }","sourceCodeStart":562,"sourceCodeEnd":598,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java#L562-L598","documentation":"Inside the cursor option object only the key 'batchSize' is supported by this agent; any other key inside cursor{} is rejected with IllegalArgumentException because there is no mapping to the MongoDB driver's AggregateIterable. This is a whitelist check guarding against silently ignored options.","triggerScenarios":"Calling aggregate with {\"cursor\":{\"batchSize\":100,\"awaitData\":true}} or {\"cursor\":{\"maxTimeMS\":5000}} — any cursor sub-key other than batchSize.","commonSituations":"Copying cursor options from the MongoDB server command spec (e.g. awaitData, maxTimeMS, tailable) which the driver's AggregateIterable does not expose via cursor{} in this agent; leftover options from a mongodump/mongotop config.","solutions":["Keep only batchSize inside the cursor object; remove all other cursor sub-keys.","Move supported concerns to top-level aggregate options (e.g. maxTimeMS→ maxTime if supported) or drop them.","Check the driver AggregateIterable API for the feature you need and upgrade the agent if it lacks support.","Wrap cursor sub-options behind a whitelist check on the client side before sending."],"exampleFix":"// before\nDocument options = new Document(\"cursor\", new Document(\"batchSize\", 100).append(\"maxTimeMS\", 5000));\n// after\nDocument options = new Document(\"cursor\", new Document(\"batchSize\", 100));","handlingStrategy":"validation","validationCode":"Document cursor = (Document) options.get(\"cursor\");\nif (cursor != null) {\n    for (String key : cursor.keySet()) {\n        if (!\"batchSize\".equals(key)) throw new IllegalArgumentException(\"Unsupported cursor option: \" + key);\n    }\n}","typeGuard":"static boolean hasOnlySupportedCursorKeys(Document cursor) {\n    return cursor == null || cursor.keySet().stream().allMatch(\"batchSize\"::equals);\n}","tryCatchPattern":"try {\n    agent.aggregate(db, collection, pipeline, options);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Unsupported MongoDB aggregate cursor option\")) {\n        ((Document) options.get(\"cursor\")).keySet().retainAll(List.of(\"batchSize\"));\n        // retry with cleaned cursor\n    } else throw e;\n}","preventionTips":["Only put batchSize inside cursor{}; move other concerns to supported top-level options","Whitelist cursor sub-keys at the config boundary","Check agent docs for supported options before adding new ones","Version-pin the agent and review the supported-option list on upgrades"],"tags":["mongodb","aggregate","unsupported-option","whitelist"],"backgroundTag":"unsupported-option","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}