github/copilot-sdk · error · IllegalArgumentException
schema must be a valid JSON object string
Error message
schema must be a valid JSON object string (must start with '{' and end with '}') What it means
When a Param is given a non-empty schema, the constructor validates that the schema string looks like a JSON object: trimmed text must start with '{' and end with '}'. Otherwise it throws this IllegalArgumentException. Only a lightweight shape check — it does not fully parse the JSON, so inner malformation is not caught here.
Solutions
- Wrap the schema in braces: "{\"type\": \"object\", ...}".
- Trim stray whitespace/quotes so the trimmed string begins with { and ends with }.
- Validate the schema with a JSON parser before constructing the Param to catch deeper errors early.
Example fix
// before
schema = "type: object, properties: { q: string }"
// after
schema = "{\"type\": \"object\", \"properties\": {\"q\": {\"type\": \"string\"}}}" Defensive patterns
Strategy: validation
Validate before calling
static void assertSchemaObject(String schema) {
if (schema != null && !schema.isEmpty()) {
String t = schema.trim();
if (!t.startsWith("{") || !t.endsWith("}"))
throw new IllegalArgumentException("schema must be a JSON object string");
new com.fasterxml.jackson.databind.ObjectMapper().readTree(t); // deeper check
}
} Type guard
static boolean isJsonObjectString(String s) {
if (s == null) return false;
String t = s.trim();
return t.startsWith("{") && t.endsWith("}");
} Try / catch
try {
new Param(name, desc, type, null, false, schema);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("schema must be a valid JSON object")) {
schema = "{" + schema.trim() + "}"; // repair missing braces, then retry
} else throw e;
} Prevention
- Always author schemas as full JSON objects with outer braces.
- Run schemas through a JSON parser/validator before Param construction.
- Do not paste YAML or prose type descriptions into the schema field.
When it happens
Trigger: new Param(..., schema="type: object") or schema="[]" or schema missing entirely from a JSON snippet (e.g. "type\": ...), i.e. any non-empty schema not delimited by braces.
Common situations: Passing a YAML or plain-text type description instead of a JSON schema, forgetting surrounding braces, wrapping the schema in quotes twice, or copying only the inner properties object without the outer {}.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- schema cannot be combined with defaultValue — express…
- required=true cannot be combined with a non-empty…
- must not be null or blank
- must be 'true' or 'false'
- tool parameter schema must be a JSON object
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/8cbaf8e6df6d927f.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/tool/Param.java:58
private final String schema;
private Param(Class<T> type, String name, String description, boolean required, String defaultValue,
String schema) {
this.type = Objects.requireNonNull(type, "type");
this.name = requireNonBlank(name, "name");
this.description = requireNonBlank(description, "description");
this.defaultValue = defaultValue == null ? "" : defaultValue;
this.schema = schema == null ? "" : schema;
this.required = required;
if (this.required && !this.defaultValue.isEmpty()) {
throw new IllegalArgumentException("required=true cannot be combined with a non-empty defaultValue");
}
if (!this.schema.isEmpty()) {
String trimmed = this.schema.trim();
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
throw new IllegalArgumentException(
"schema must be a valid JSON object string (must start with '{' and end with '}')");
}
if (!this.defaultValue.isEmpty()) {
throw new IllegalArgumentException(
"schema cannot be combined with defaultValue — express defaults inside the schema if needed");
}
}
validateDefaultValue(type, this.defaultValue);
}
/**
* Creates a required parameter with no default value.
*
* @param <T>
* the parameter type
* @param type
* the Java class of the parameterView on GitHub (pinned to cd8cf15dc3)