{"record":{"id":"8cbaf8e6df6d927f","repo":"github/copilot-sdk","slug":"schema-must-be-a-valid-json-object-string-must-st","errorCode":null,"errorMessage":"schema must be a valid JSON object string (must start with '{' and end with '}')","messagePattern":"schema must be a valid JSON object string \\(must start with '(.+?)'\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/tool/Param.java","lineNumber":58,"sourceCode":"    private final String schema;\n\n    private Param(Class<T> type, String name, String description, boolean required, String defaultValue,\n            String schema) {\n        this.type = Objects.requireNonNull(type, \"type\");\n        this.name = requireNonBlank(name, \"name\");\n        this.description = requireNonBlank(description, \"description\");\n        this.defaultValue = defaultValue == null ? \"\" : defaultValue;\n        this.schema = schema == null ? \"\" : schema;\n        this.required = required;\n\n        if (this.required && !this.defaultValue.isEmpty()) {\n            throw new IllegalArgumentException(\"required=true cannot be combined with a non-empty defaultValue\");\n        }\n\n        if (!this.schema.isEmpty()) {\n            String trimmed = this.schema.trim();\n            if (!trimmed.startsWith(\"{\") || !trimmed.endsWith(\"}\")) {\n                throw new IllegalArgumentException(\n                        \"schema must be a valid JSON object string (must start with '{' and end with '}')\");\n            }\n            if (!this.defaultValue.isEmpty()) {\n                throw new IllegalArgumentException(\n                        \"schema cannot be combined with defaultValue — express defaults inside the schema if needed\");\n            }\n        }\n\n        validateDefaultValue(type, this.defaultValue);\n    }\n\n    /**\n     * Creates a required parameter with no default value.\n     *\n     * @param <T>\n     *            the parameter type\n     * @param type\n     *            the Java class of the parameter","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/tool/Param.java#L40-L76","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 {}.","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."],"exampleFix":"// before\nschema = \"type: object, properties: { q: string }\"\n// after\nschema = \"{\\\"type\\\": \\\"object\\\", \\\"properties\\\": {\\\"q\\\": {\\\"type\\\": \\\"string\\\"}}}\"","handlingStrategy":"validation","validationCode":"static void assertSchemaObject(String schema) {\n    if (schema != null && !schema.isEmpty()) {\n        String t = schema.trim();\n        if (!t.startsWith(\"{\") || !t.endsWith(\"}\"))\n            throw new IllegalArgumentException(\"schema must be a JSON object string\");\n        new com.fasterxml.jackson.databind.ObjectMapper().readTree(t); // deeper check\n    }\n}","typeGuard":"static boolean isJsonObjectString(String s) {\n    if (s == null) return false;\n    String t = s.trim();\n    return t.startsWith(\"{\") && t.endsWith(\"}\");\n}","tryCatchPattern":"try {\n    new Param(name, desc, type, null, false, schema);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"schema must be a valid JSON object\")) {\n        schema = \"{\" + schema.trim() + \"}\"; // repair missing braces, then retry\n    } else throw e;\n}","preventionTips":["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."],"tags":["validation","json-schema","tool-parameters","format"],"backgroundTag":"schema-validation-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}