github/copilot-sdk · error · IllegalArgumentException
A Param descriptor is null for tool ' + toolName + '
Error message
A Param descriptor is null for tool ' + toolName + '
What it means
Thrown by ParamSchema.buildSchema during validation when the params array passed for a tool contains a null element. buildSchema validates that every Param descriptor is non-null and that names are unique before generating the JSON schema. It is a fail-fast guard against tool registration bugs.
Solutions
- Remove null entries before calling buildSchema: params.removeIf(Objects::isNull)
- Fix the factory/builder that produced a null Param instead of a descriptor
- Assert all params non-null in tool registration tests
- Catch IllegalArgumentException and log toolName to identify the misregistered tool
Example fix
// before
List<Param<?>> params = Arrays.asList(p1, null, p3);
ParamSchema.buildSchema("myTool", params); // throws
// after
List<Param<?>> params = Arrays.asList(p1, p3);
ParamSchema.buildSchema("myTool", params); Defensive patterns
Strategy: validation
Validate before calling
if (params.stream().anyMatch(Objects::isNull)) { throw new IllegalStateException("null Param in " + toolName); } Type guard
boolean hasNoNullParams(List<Param<?>> ps) { return ps != null && ps.stream().noneMatch(Objects::isNull); } Try / catch
try { schema = ParamSchema.buildSchema(toolName, params); } catch (IllegalArgumentException e) { throw new ToolRegistrationException(toolName, e); } Prevention
- Filter nulls with params.removeIf(Objects::isNull) before registration
- Make Param factories non-null-returning (throw internally instead)
- Add registration unit tests for every tool
When it happens
Trigger: Calling buildSchema(toolName, params) with a list containing null — e.g. a Param created conditionally and left null, or arrays assembled with placeholder nulls.
Common situations: Programmatic tool registration where a factory method returns null; refactors that remove a Param but leave a null slot; reflection/annotation-processor gaps producing null descriptors.
Related errors
- Duplicate parameter name ' + param.name() + ' in tool ' +…
- Invalid schema JSON for parameter ' + param.name() + ' in…
- Unknown AgentMode value: + value
- Unknown AskUserVariant value: + value
- Unknown AutoTier value: + value
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/a0fa59e201b5914c.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/rpc/ParamSchema.java:76
* the configured {@link ObjectMapper} used to coerce default values
* into their typed form for the schema
* @param params
* zero or more parameter descriptors
* @return a JSON Schema object map with {@code type=object},
* {@code properties}, and {@code required} keys
* @throws IllegalArgumentException
* if a null param or duplicate parameter names are found
*/
static Map<String, Object> buildSchema(String toolName, ObjectMapper mapper, Param<?>... params) {
if (params == null || params.length == 0) {
return Map.of("type", "object", "properties", Map.of(), "required", List.of());
}
// Validate: no null params, no duplicate names
Set<String> seen = new HashSet<>();
for (Param<?> param : params) {
if (param == null) {
throw new IllegalArgumentException("A Param descriptor is null for tool '" + toolName + "'");
}
if (!seen.add(param.name())) {
throw new IllegalArgumentException(
"Duplicate parameter name '" + param.name() + "' in tool '" + toolName + "'");
}
}
List<String> requiredNames = new ArrayList<>();
Map<String, Object> properties = new LinkedHashMap<>();
for (Param<?> param : params) {
Map<String, Object> typeSchema;
if (!param.schema().isEmpty()) {
try {
@SuppressWarnings("unchecked")
Map<String, Object> parsed = mapper.readerFor(Map.class)
.with(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
.with(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS).readValue(param.schema());View on GitHub (pinned to cd8cf15dc3)