github/copilot-sdk · error · IllegalArgumentException
Failed to deserialize arguments to + type.getName()
Error message
Failed to deserialize arguments to + type.getName()
What it means
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.
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)).
Example fix
// before
SearchArgs a = invocation.getArgumentsAs(SearchArgs.class); // fails on unexpected field
// after
@JsonIgnoreProperties(ignoreUnknown = true)
class SearchArgs { public String query; }
SearchArgs a = invocation.getArgumentsAs(SearchArgs.class); Defensive patterns
Strategy: validation
Validate before calling
if (invocation.getArgumentsNode() == null) throw new IllegalStateException("no arguments provided");
JsonNode n = invocation.getArgumentsNode();
if (!n.hasNonNull("query")) throw new IllegalArgumentException("missing 'query' argument"); Type guard
static <T> T safeArgs(ToolInvocation inv, Class<T> type) {
try { return inv.getArgumentsAs(type); }
catch (IllegalArgumentException e) { log.warn("bad arguments", e.getCause()); return null; }
} Try / catch
try { SearchArgs a = invocation.getArgumentsAs(SearchArgs.class); }
catch (IllegalArgumentException e) {
log.error("argument deserialization failed: {}", e.getCause().getMessage());
return ToolResultObject.of("error", "invalid arguments");
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- Failed to serialize FFI JSON parameter.
- Required parameter ' + param.name() + ' is missing from…
- Parameter ' + param.name() + ' expected a numeric value for…
- Failed to coerce parameter ' + param.name() + ' to type +…
- Failed to serialize tool result to JSON
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/4ab83763757d00e7.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/rpc/ToolInvocation.java:161
* // In your tool handler
* WeatherArgs args = invocation.getArgumentsAs(WeatherArgs.class);
* String city = args.city();
* }</pre>
*
* @param <T>
* the type to deserialize to
* @param type
* the class of the target type
* @return the arguments deserialized as the specified type
* @throws IllegalArgumentException
* if deserialization fails
* @since 1.0.0
*/
public <T> T getArgumentsAs(Class<T> type) {
try {
return MAPPER.treeToValue(argumentsNode, type);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to deserialize arguments to " + type.getName(), e);
}
}
/**
* Sets the tool arguments.
* <p>
* <strong>Note:</strong> This method is intended for internal SDK use and JSON
* deserialization. Users typically do not need to call this method directly.
*
* @param arguments
* the arguments as a JsonNode
* @return this invocation for method chaining
*/
@JsonSetter("arguments")
public ToolInvocation setArguments(JsonNode arguments) {
this.argumentsNode = arguments;
return this;
}View on GitHub (pinned to cd8cf15dc3)