github/copilot-sdk · error · IllegalArgumentException
Invalid schema JSON for parameter ' + param.name() + ' in…
Error message
Invalid schema JSON for parameter ' + param.name() + ' in tool ' + toolName + ': + e.getMessage()
What it means
Thrown by ParamSchema.buildSchema when a Param supplies a custom schema() JSON string that cannot be parsed by Jackson (with FAIL_ON_TRAILING_TOKENS and USE_BIG_DECIMAL_FOR_FLOATS enabled). The message includes the parameter name, tool name, and Jackson's parse error, so invalid schema text is rejected at registration time instead of producing a broken tool schema.
Solutions
- Validate the schema string with a JSON linter/parse before registering the tool
- Ensure schema() is exactly one JSON object (no trailing tokens, no leading BOM)
- Generate the schema programmatically (forType / Map.of) instead of a hand-written string
- Read e.getMessage() in the error — it pinpoints the exact offset and reason Jackson failed
Example fix
// before
param.schema = "{\"type\":\"string\"} extra"; // trailing token
// after
param.schema = "{\"type\":\"string\"}"; Defensive patterns
Strategy: validation
Validate before calling
new ObjectMapper().readerFor(Map.class).readValue(param.schema()); // pre-validate custom schema JSON
Type guard
boolean isValidJsonObject(String s) { try { new ObjectMapper().readValue(s, Map.class); return true; } catch (Exception e) { return false; } } Try / catch
try { schema = ParamSchema.buildSchema(toolName, params); } catch (IllegalArgumentException e) { /* e.getMessage() contains the Jackson parse error and offset */ throw new ToolRegistrationException(toolName, e); } Prevention
- Lint hand-written JSON schema strings before committing them
- Generate schema maps programmatically instead of string literals
- Keep FAIL_ON_TRAILING_TOKENS semantics in mind: exactly one JSON object, no trailing text
When it happens
Trigger: Passing schema() text that is not a single valid JSON object — malformed JSON, trailing garbage after the object, multiple JSON values concatenated, or an array/scalar instead of an object map.
Common situations: Hand-authored JSON Schema snippets with missing braces or trailing commas; embedding JSON in properties files where escaping is lost; concatenating two schema strings.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- Failed to apply default value ' + defaultValue + ' for…
- A Param descriptor is null for tool ' + toolName + '
- Duplicate parameter name ' + param.name() + ' in tool ' +…
- Failed to serialize FFI JSON parameter.
- Unknown AgentMode value: + value
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/4430c4d863a60368.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/rpc/ParamSchema.java:97
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());
typeSchema = parsed;
} catch (Exception e) {
throw new IllegalArgumentException("Invalid schema JSON for parameter '" + param.name()
+ "' in tool '" + toolName + "': " + e.getMessage(), e);
}
} else {
typeSchema = forType(param.type());
}
Map<String, Object> enriched = new LinkedHashMap<>(typeSchema);
enriched.put("description", param.description());
if (param.hasDefaultValue()) {
enriched.put("default", ParamCoercion.coerceDefault(param, mapper));
}
properties.put(param.name(), Collections.unmodifiableMap(enriched));
if (param.required()) {
requiredNames.add(param.name());
}
}
return Map.of("type", "object", "properties", Collections.unmodifiableMap(properties), "required",
Collections.unmodifiableList(requiredNames));View on GitHub (pinned to cd8cf15dc3)