github/copilot-sdk · error · IllegalArgumentException
Required parameter ' + param.name() + ' is missing from…
Error message
Required parameter ' + param.name() + ' is missing from tool invocation
What it means
ParamCoercion.coerce converts raw JSON tool-invocation arguments into typed Java parameters. When a raw argument is null and the ToolParameter is marked required (with no default value), the library throws IllegalArgumentException because a required tool parameter was not supplied by the model/caller.
Solutions
- Mark the parameter as required in the tool's JSON Schema ("required": [name]) so the model is forced to supply it.
- Give the parameter a default value via hasDefaultValue/coerceDefault if it can reasonably be defaulted.
- Validate the arguments map against the tool's parameter list before dispatching and return a clear tool error to the model.
- If the parameter should be optional, change required=false or use Optional/nullable types so emptyOptionalOrNull is returned instead.
Example fix
// before
@ToolParameter(name = "path", required = true)
// schema generated without required -> model omits it
// after
// ensure generated schema includes: {"type":"object","required":["path"],...}
// and/or provide a default:
@ToolParameter(name = "path", required = true, defaultValue = ".") Defensive patterns
Strategy: validation
Validate before calling
for (ToolParameter p : tool.parameters()) {
if (p.required() && !p.hasDefaultValue() && !args.containsKey(p.name())) {
throw new ToolInvocationException("missing required argument: " + p.name());
}
} Type guard
static boolean hasRequiredArgs(Map<String,Object> args, List<ToolParameter> params) {
return params.stream()
.filter(ToolParameter::required)
.filter(p -> !p.hasDefaultValue())
.allMatch(p -> args.get(p.name()) != null);
} Try / catch
try {
Object v = ParamCoercion.coerce(param, raw, mapper);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("is missing from tool invocation")) {
return toolError("missing required parameter: " + param.name());
}
throw e;
} Prevention
- Emit "required": [param] in each tool's JSON Schema so models supply mandatory arguments
- Validate the arguments map against the tool signature before dispatch
- Provide defaultValue for parameters that can sensibly default
- Return a structured tool error so the model can retry with the missing argument
When it happens
Trigger: Invoking a registered tool where a @ToolParameter(required=true) argument is absent from the arguments object or explicitly null — e.g. the LLM omitted the key or sent {"path": null}.
Common situations: Models omitting optional-seeming arguments the developer marked required; schema/JSON-Schema not declaring the parameter required so the model drops it; callers invoking tools programmatically with incomplete maps; renaming a parameter so the old key no longer matches.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Unknown AgentMode value: + value
- Unknown AskUserVariant value: + value
- Unknown AutoTier value: + value
- Unknown MessageSource value: + value
- Parameter ' + param.name() + ' expected a numeric value for…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/92a820a2edd500d4.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/rpc/ParamCoercion.java:70
* @param param
* the parameter descriptor
* @param mapper
* the configured {@link ObjectMapper} for complex type conversion
* @return the coerced argument value
* @throws IllegalArgumentException
* if a required parameter is missing or coercion fails
*/
@SuppressWarnings("unchecked")
static <T> T coerce(Map<String, Object> args, Param<T> param, ObjectMapper mapper) {
Object raw = (args != null) ? args.get(param.name()) : null;
if (raw == null) {
if (param.hasDefaultValue()) {
return coerceDefault(param, mapper);
} else if (!param.required()) {
return (T) emptyOptionalOrNull(param.type());
} else {
throw new IllegalArgumentException(
"Required parameter '" + param.name() + "' is missing from tool invocation");
}
}
Class<T> type = param.type();
// Handle Optional* types explicitly before delegating to ObjectMapper
if (type == java.util.OptionalInt.class) {
try {
return (T) java.util.OptionalInt.of(((Number) raw).intValue());
} catch (ClassCastException ex) {
throw new IllegalArgumentException("Parameter '" + param.name()
+ "' expected a numeric value for OptionalInt, got: " + raw.getClass().getSimpleName(), ex);
}
}
if (type == java.util.OptionalLong.class) {
try {
return (T) java.util.OptionalLong.of(((Number) raw).longValue());View on GitHub (pinned to cd8cf15dc3)