{"record":{"id":"3401c5cd7bdbad76","repo":"jd-opensource/joyagent-jdgenie","slug":"input-must-be-a-map","errorCode":null,"errorMessage":"Input must be a Map","messagePattern":"Input must be a Map","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"genie-backend/src/main/java/com/jd/genie/agent/tool/common/PlanningTool.java","lineNumber":122,"sourceCode":"    private Map<String, Object> getStepStatusProperty() {\n        Map<String, Object> stepStatus = new HashMap<>();\n        stepStatus.put(\"type\", \"string\");\n        stepStatus.put(\"enum\", Arrays.asList(\"not_started\", \"in_progress\", \"completed\", \"blocked\"));\n        stepStatus.put(\"description\", \"Status to set for a step. Used with mark_step command.\");\n        return stepStatus;\n    }\n\n    private Map<String, Object> getStepNotesProperty() {\n        Map<String, Object> stepNotes = new HashMap<>();\n        stepNotes.put(\"type\", \"string\");\n        stepNotes.put(\"description\", \"Additional notes for a step. Optional for mark_step command.\");\n        return stepNotes;\n    }\n\n    @Override\n    public Object execute(Object input) {\n        if (!(input instanceof Map)) {\n            throw new IllegalArgumentException(\"Input must be a Map\");\n        }\n\n        Map<String, Object> params = (Map<String, Object>) input;\n        String command = (String) params.get(\"command\");\n\n        if (command == null || command.isEmpty()) {\n            throw new IllegalArgumentException(\"Command is required\");\n        }\n\n        Function<Map<String, Object>, String> handler = commandHandlers.get(command);\n        if (handler != null) {\n            return handler.apply(params);\n        } else {\n            throw new IllegalArgumentException(\"Unknown command: \" + command);\n        }\n    }\n\n    private String createPlan(Map<String, Object> params) {","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/jd-opensource/joyagent-jdgenie/blob/2417e0b8b636d941ad5fb14c59b20dddfef5375d/genie-backend/src/main/java/com/jd/genie/agent/tool/common/PlanningTool.java#L104-L140","documentation":"PlanningTool.execute requires the input to be a Map of parameters; any other type (String, List, null) throws IllegalArgumentException. It enforces the tool's parameter contract before dispatching to a command handler.","triggerScenarios":"Calling PlanningTool.execute with a raw JSON string, a list, or null instead of a Map<String,Object> of parameters.","commonSituations":"Passing the unparsed JSON body directly to execute, framework deserializing arguments differently than expected, or programmatic misuse of the tool API.","solutions":["Parse the input JSON into a Map before calling execute","Check instanceof Map before invocation","Ensure the caller serializes tool arguments as an object, not a string"],"exampleFix":"// before\nString out = planningTool.execute(rawJsonString);\n// after\nMap<String,Object> params = objectMapper.readValue(rawJsonString, new TypeReference<Map<String,Object>>(){});\nString out = planningTool.execute(params);","handlingStrategy":"type-guard","validationCode":"if (!(input instanceof Map)) { throw new IllegalArgumentException(\"expected Map\"); }","typeGuard":"boolean isParamMap(Object o) { return o instanceof Map; }","tryCatchPattern":"try {\n    return planningTool.execute(input);\n} catch (IllegalArgumentException e) {\n    input = objectMapper.readValue(String.valueOf(input), Map.class);\n    return planningTool.execute(input);\n}","preventionTips":["Parse JSON arguments to a Map before calling execute","Enforce object-typed tool arguments in the LLM schema","Add instanceof checks at call boundaries"],"tags":["java","tool","input-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"2417e0b8b636d941ad5fb14c59b20dddfef5375d","analyzedAt":"2026-09-08T11:28:19.414Z","contentChangedAt":"2026-09-08T11:28:19.414Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}