{"record":{"id":"7764b1a61ce8d2e6","repo":"github/copilot-sdk","slug":"tool-parameter-schema-must-be-a-json-object","errorCode":null,"errorMessage":"tool parameter schema must be a JSON object","messagePattern":"tool parameter schema must be a JSON object","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust/src/tool.rs","lineNumber":83,"sourceCode":"/// `serde_json::json!(...)` literal.\n///\n/// Use [`try_tool_parameters`] when the schema comes from dynamic input and\n/// should return a recoverable error instead of panicking.\n///\n/// # Example\n///\n/// ```rust\n/// use github_copilot_sdk::tool::tool_parameters;\n/// use github_copilot_sdk::Tool;\n///\n/// let mut tool = Tool::default();\n/// tool.name = \"ping\".to_string();\n/// tool.description = \"ping the server\".to_string();\n/// tool.parameters = tool_parameters(serde_json::json!({\"type\": \"object\"}));\n/// # let _ = tool;\n/// ```\npub fn tool_parameters(schema: serde_json::Value) -> IndexMap<String, serde_json::Value> {\n    try_tool_parameters(schema).expect(\"tool parameter schema must be a JSON object\")\n}\n\n/// Fallible variant of [`tool_parameters`] for callers handling dynamic schema input.\npub fn try_tool_parameters(\n    schema: serde_json::Value,\n) -> Result<IndexMap<String, serde_json::Value>, serde_json::Error> {\n    serde_json::from_value(schema)\n}\n\n/// Convert an MCP `CallToolResult` JSON value into a Copilot tool result.\n///\n/// Returns `None` when the value is not shaped like a `CallToolResult`.\npub fn convert_mcp_call_tool_result(value: &serde_json::Value) -> Option<ToolResult> {\n    let content = value.get(\"content\")?.as_array()?;\n    let mut text_parts = Vec::new();\n    let mut binary_results = Vec::new();\n\n    for block in content {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/rust/src/tool.rs#L65-L101","documentation":"tool_parameters converts a JSON Schema object into an ordered parameter map and is the infallible convenience wrapper over try_tool_parameters. It panics via .expect() when the schema is not a JSON object (e.g. an array, string, or null), because a tool parameter schema must be an object per the MCP spec.","triggerScenarios":"Calling tool_parameters with a JSON value that is not an object — serde_json::json!(null), a schema read from a file that is an array, or a dynamically built schema that ended up as something other than an object.","commonSituations":"Loading schemas from untrusted/dynamic sources; typos producing json!([\"type\",\"object\"]) instead of json!({\"type\":\"object\"}); passing Value::Null when a schema is absent.","solutions":["Use try_tool_parameters and handle the Err instead of panicking on dynamic input","Ensure the schema is a JSON object before calling: verify value.is_object()","Fix the schema construction so the top level is {\"type\":\"object\", ...}","Validate schema files/inputs at load time before passing to tool_parameters"],"exampleFix":"// before\nlet params = tool_parameters(loaded_schema); // panics if loaded_schema isn't an object\n// after\nlet params = try_tool_parameters(loaded_schema)\n    .expect(\"tool parameter schema must be a JSON object\"); // or handle Err gracefully","handlingStrategy":"validation","validationCode":"// Rust\nfn safe_tool_parameters(schema: serde_json::Value) -> Option<IndexMap<String, serde_json::Value>> {\n    if !schema.is_object() { return None; }\n    try_tool_parameters(schema).ok()\n}","typeGuard":"// Rust\nfn is_json_object(v: &serde_json::Value) -> bool { v.is_object() }","tryCatchPattern":null,"preventionTips":["Always build schemas starting from json!({\"type\": \"object\"})","Use try_tool_parameters for any schema from dynamic/external sources","Validate schema files at load time","Never pass serde_json::Value::Null as a schema"],"tags":["rust","json-schema","panic","validation"],"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"}