{"record":{"id":"bd418b044c39d9e2","repo":"siyuan-note/siyuan","slug":"root-type-must-be-object","errorCode":null,"errorMessage":"root type must be \"object\"","messagePattern":"root type must be \"object\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/validation.go","lineNumber":99,"sourceCode":"\t}\n\tvar raw any\n\tif err = json.Unmarshal(data, &raw); err != nil {\n\t\treturn nil, err\n\t}\n\tif err = validateJSONComplexity(raw, maxToolSchemaDepth, maxToolSchemaNodes); err != nil {\n\t\treturn nil, err\n\t}\n\tif requireObject {\n\t\tif err = validateParamHeaderAnnotations(raw); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tvar parsed jsonschema.Schema\n\tif err = json.Unmarshal(data, &parsed); err != nil {\n\t\treturn nil, err\n\t}\n\tif requireObject && parsed.Type != \"object\" {\n\t\treturn nil, fmt.Errorf(`root type must be \"object\"`)\n\t}\n\treturn parsed.Resolve(nil)\n}\n\nfunc (validator *ToolValidator) ValidateInput(arguments map[string]any) error {\n\treturn validator.ValidateInputContext(context.Background(), arguments)\n}\n\nfunc (validator *ToolValidator) ValidateInputContext(ctx context.Context, arguments map[string]any) error {\n\tif validator == nil || validator.input == nil {\n\t\treturn nil\n\t}\n\tvalue, err := prepareValidationValue(arguments)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn validateResolved(ctx, validator.validationSlots, validator.input, value)\n}","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/tools/validation.go#L81-L117","documentation":"Thrown by resolveToolSchema when requireObject is true (input schemas only) and the parsed jsonschema.Schema's Type field is not the literal \"object\". The MCP specification mandates that a tool's inputSchema be a JSON Schema of type object whose properties describe the named arguments; anything else is rejected before Resolve runs.","triggerScenarios":"Registering a tool whose InputSchema has type \"string\", \"array\", \"number\", is missing a type, or is an empty/non-object schema. CompileToolValidator always passes requireObject=true for input schemas.","commonSituations":"A developer copies an output/result schema (which may be any type) into the input slot; a tool is registered with InputSchema set to a fragment like {\"type\":\"array\"}; the schema is built dynamically and the object wrapper is omitted.","solutions":["Wrap the input schema as {\"type\":\"object\",\"properties\":{...}} with the actual parameters under properties.","If the tool takes no arguments, use {\"type\":\"object\",\"properties\":{}} (an empty object schema) rather than null or an empty map.","Verify you are assigning to InputSchema, not OutputSchema — output schemas allow non-object root types."],"exampleFix":"// before\nInputSchema: ToolSchema{Raw: map[string]any{\"type\": \"array\"}}\n// after\nInputSchema: ToolSchema{Raw: map[string]any{\"type\": \"object\", \"properties\": map[string]any{}}}","handlingStrategy":"validation","validationCode":"if t, _ := schema[\"type\"].(string); t != \"object\" {\n    schema[\"type\"] = \"object\"\n    if _, ok := schema[\"properties\"]; !ok { schema[\"properties\"] = map[string]any{} }\n}","typeGuard":"func isObjectSchema(schema map[string]any) bool {\n    t, _ := schema[\"type\"].(string)\n    return t == \"object\"\n}","tryCatchPattern":null,"preventionTips":["Always build input schemas from an object skeleton {\"type\":\"object\",\"properties\":{...}}.","Keep a shared helper that constructs a valid input-schema envelope for tools.","Unit-test CompileToolValidator on each tool to catch type errors at registration time."],"tags":["mcp","json-schema","validation","input-schema"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}