{"record":{"id":"4ab83763757d00e7","repo":"github/copilot-sdk","slug":"failed-to-deserialize-arguments-to-type-getname","errorCode":null,"errorMessage":"Failed to deserialize arguments to  + type.getName()","messagePattern":"Failed to deserialize arguments to  \\+ type\\.getName\\(\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/rpc/ToolInvocation.java","lineNumber":161,"sourceCode":"     * // In your tool handler\n     * WeatherArgs args = invocation.getArgumentsAs(WeatherArgs.class);\n     * String city = args.city();\n     * }</pre>\n     *\n     * @param <T>\n     *            the type to deserialize to\n     * @param type\n     *            the class of the target type\n     * @return the arguments deserialized as the specified type\n     * @throws IllegalArgumentException\n     *             if deserialization fails\n     * @since 1.0.0\n     */\n    public <T> T getArgumentsAs(Class<T> type) {\n        try {\n            return MAPPER.treeToValue(argumentsNode, type);\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\"Failed to deserialize arguments to \" + type.getName(), e);\n        }\n    }\n\n    /**\n     * Sets the tool arguments.\n     * <p>\n     * <strong>Note:</strong> This method is intended for internal SDK use and JSON\n     * deserialization. Users typically do not need to call this method directly.\n     *\n     * @param arguments\n     *            the arguments as a JsonNode\n     * @return this invocation for method chaining\n     */\n    @JsonSetter(\"arguments\")\n    public ToolInvocation setArguments(JsonNode arguments) {\n        this.argumentsNode = arguments;\n        return this;\n    }","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/rpc/ToolInvocation.java#L143-L179","documentation":"ToolInvocation.getArgumentsAs(type) deserializes the tool's JSON arguments node into the requested type via Jackson's treeToValue. If the arguments JSON does not map onto the target type (missing/extra incompatible fields, wrong shapes, malformed data, or null argumentsNode), the exception is wrapped in an IllegalArgumentException with this message naming the target type.","triggerScenarios":"Calling invocation.getArgumentsAs(MyDto.class) where the client-sent arguments don't match MyDto (e.g. string where an int is expected, nested object vs scalar), argumentsNode is null, or the DTO has incompatible Jackson expectations (unknown properties without FAIL_ON_UNKNOWN_PROPERTIES disabled, missing no-arg constructor).","commonSituations":"LLM sending slightly wrong argument shapes (common with loosely-specified schemas); renaming DTO fields after the tool schema was published; deserializing into records/classes lacking Jackson-compatible constructors; invoking the method before arguments were set.","solutions":["Inspect the cause (JsonProcessingException/JsonMappingException) to see which field/path failed to map.","Use readTree/getArgumentsNode to validate the expected fields exist and have the right types before calling getArgumentsAs.","Align the tool's parameter schema (registered in ToolDefinition) with the target DTO's fields and types.","Make the DTO Jackson-friendly: default constructor (or @JsonCreator), correct field names, tolerant config (@JsonIgnoreProperties(ignoreUnknown=true))."],"exampleFix":"// before\nSearchArgs a = invocation.getArgumentsAs(SearchArgs.class); // fails on unexpected field\n\n// after\n@JsonIgnoreProperties(ignoreUnknown = true)\nclass SearchArgs { public String query; }\nSearchArgs a = invocation.getArgumentsAs(SearchArgs.class);","handlingStrategy":"validation","validationCode":"if (invocation.getArgumentsNode() == null) throw new IllegalStateException(\"no arguments provided\");\nJsonNode n = invocation.getArgumentsNode();\nif (!n.hasNonNull(\"query\")) throw new IllegalArgumentException(\"missing 'query' argument\");","typeGuard":"static <T> T safeArgs(ToolInvocation inv, Class<T> type) {\n  try { return inv.getArgumentsAs(type); }\n  catch (IllegalArgumentException e) { log.warn(\"bad arguments\", e.getCause()); return null; }\n}","tryCatchPattern":"try { SearchArgs a = invocation.getArgumentsAs(SearchArgs.class); }\ncatch (IllegalArgumentException e) {\n  log.error(\"argument deserialization failed: {}\", e.getCause().getMessage());\n  return ToolResultObject.of(\"error\", \"invalid arguments\");\n}","preventionTips":["Keep the tool's declared parameter schema in sync with the DTO fields.","Annotate DTOs with @JsonIgnoreProperties(ignoreUnknown = true).","Validate required fields from the arguments tree before typed deserialization.","Test handlers with representative LLM-generated argument payloads."],"tags":["java","jackson","json-deserialization","tool-invocation"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}