{"record":{"id":"052b9c92705a4cf3","repo":"t8y2/dbx","slug":"mongodb-aggregate-option-explain-must-be-a-boolean","errorCode":null,"errorMessage":"MongoDB aggregate option explain must be a boolean","messagePattern":"MongoDB aggregate option explain must be a boolean","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java","lineNumber":548,"sourceCode":"                throw new IllegalArgumentException(\"Each MongoDB aggregate pipeline stage must be an object\");\n            }\n            pipeline.add(Document.parse(stage.toString()));\n        }\n        return pipeline;\n    }\n\n    static Document aggregateOptions(JsonObject params) {\n        Document options = documentOrNull(params, \"options\");\n        return options == null ? new Document() : options;\n    }\n\n    static boolean aggregateExplain(Document options) {\n        Object explain = options.get(\"explain\");\n        if (explain == null) {\n            return false;\n        }\n        if (!(explain instanceof Boolean)) {\n            throw new IllegalArgumentException(\"MongoDB aggregate option explain must be a boolean\");\n        }\n        return (Boolean) explain;\n    }\n\n    static Document buildAggregateCommand(String collection, List<Document> pipeline, Document options) {\n        validateAggregateOptions(options);\n        Document command = new Document(\"aggregate\", collection).append(\"pipeline\", pipeline);\n        for (Map.Entry<String, Object> entry : options.entrySet()) {\n            command.append(entry.getKey(), entry.getValue());\n        }\n        if (!aggregateExplain(options) && !command.containsKey(\"cursor\")) {\n            command.append(\"cursor\", new Document());\n        }\n        return command;\n    }\n\n    private static AggregateIterable<Document> applyAggregateOptions(\n        AggregateIterable<Document> iterable,","sourceCodeStart":530,"sourceCodeEnd":566,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java#L530-L566","documentation":"MongoAgent.validateAggregateOptions/aggregateExplain requires the 'explain' aggregate option to be a JSON boolean (true or false) because it is passed directly to the MongoDB driver's explain flag. Passing any other type (string \"true\", number, object) makes the command document invalid for the driver, so the library throws IllegalArgumentException before sending anything to the server. This is an eager input-type check to fail fast with a clear message.","triggerScenarios":"Calling the aggregate tool/command with options.explain set to a non-boolean, e.g. {\"explain\": \"true\"}, {\"explain\": 1}, or {\"explain\": null}? No — null is treated as absent; the throw happens for any non-Boolean, non-null value like a string or number.","commonSituations":"Config read from JSON/YAML where explain was quoted as a string; env-var-driven config parsed as text; hand-written JSON in an MCP client where 1/0 was used instead of true/false; template interpolation turning a boolean into a string.","solutions":["Change the explain value to a real boolean: true or false (unquoted) in the options document.","If the value comes from config/env, coerce it with Boolean.parseBoolean (or a strict parse) before building the options Document.","Remove the explain option entirely if you did not intend to explain — omitting it defaults to false.","Validate the options payload schema at the client boundary before calling the agent."],"exampleFix":"// before\nDocument options = new Document(\"explain\", \"true\");\n// after\nDocument options = new Document(\"explain\", Boolean.parseBoolean(String.valueOf(rawExplain)));","handlingStrategy":"validation","validationCode":"Object explain = options.get(\"explain\");\nif (explain != null && !(explain instanceof Boolean)) {\n    throw new IllegalArgumentException(\"explain must be a boolean, got: \" + explain.getClass().getSimpleName());\n}","typeGuard":"static boolean isBoolean(Object v) {\n    return v == null || v instanceof Boolean;\n}","tryCatchPattern":"try {\n    agent.aggregate(db, collection, pipeline, options);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"explain must be a boolean\")) {\n        options.put(\"explain\", Boolean.parseBoolean(String.valueOf(options.get(\"explain\"))));\n        // retry or surface a typed validation error\n    } else throw e;\n}","preventionTips":["Never quote booleans in JSON/YAML config for driver options","Parse config booleans with a strict parser (only \"true\"/\"false\" accepted)","Validate the aggregate options payload against a schema before calling the agent","Log the offending value's type when coercion fails"],"tags":["mongodb","aggregate","type-validation","illegal-argument"],"backgroundTag":"invalid-option-type","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"}