siyuan-note/siyuan · error
root type must be "object"
Error message
root type must be "object"
What it means
MCP tool input schemas must describe an object of named arguments. When compiling an input schema (requireObject=true), resolveToolSchema checks the parsed schema's Type field and rejects any root that is not "object". Output schemas are exempt from this check.
Solutions
- Set InputSchema.Type to "object"; for tools with no arguments use an object schema with no properties.
- Verify the field is set on InputSchema (not only OutputSchema) when constructing ToolSchema manually.
- Check the wrapped compile error — this message appears as the inner error of 'invalid input schema'.
- Add a registration-time unit test calling CompileToolValidator for every tool.
Example fix
// before
InputSchema: ToolSchema{Properties: map[string]Property{...}} // Type unset
// after
InputSchema: ToolSchema{Type: "object", Properties: map[string]Property{...}} Defensive patterns
Strategy: type-guard
Validate before calling
if (tool.InputSchema?.type !== "object") {
throw new Error("tool input schema root must be of type object");
} Type guard
func inputSchemaIsObject(t *Tool) bool {
return t != nil && t.InputSchema.Type == "object"
} Prevention
- Always initialize InputSchema with Type: "object", even for zero-argument tools.
- Do not reuse output schemas as input schemas — the root-type rule differs.
- Lint tool declarations for missing Type fields before registration.
When it happens
Trigger: Registering a tool whose InputSchema.Type is missing, empty, or set to something other than "object" (e.g. "string", "array", or absent) — the schema unmarshals fine but fails the root-type gate in resolveToolSchema.
Common situations: Copy-pasting an output schema (which may have any root type) into the InputSchema slot; building ToolSchema programmatically and forgetting to set Type; simplifying a no-argument tool to Type:"null" or leaving it empty instead of an empty object schema.
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
- invalid input schema
- invalid output schema
- property : duplicate x-mcp-header value
- property : x-mcp-header can only be applied to primitive…
- property : x-mcp-header must be a non-empty string
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/bd418b044c39d9e2.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/tools/validation.go:99
}
var raw any
if err = json.Unmarshal(data, &raw); err != nil {
return nil, err
}
if err = validateJSONComplexity(raw, maxToolSchemaDepth, maxToolSchemaNodes); err != nil {
return nil, err
}
if requireObject {
if err = validateParamHeaderAnnotations(raw); err != nil {
return nil, err
}
}
var parsed jsonschema.Schema
if err = json.Unmarshal(data, &parsed); err != nil {
return nil, err
}
if requireObject && parsed.Type != "object" {
return nil, fmt.Errorf(`root type must be "object"`)
}
return parsed.Resolve(nil)
}
func (validator *ToolValidator) ValidateInput(arguments map[string]any) error {
return validator.ValidateInputContext(context.Background(), arguments)
}
func (validator *ToolValidator) ValidateInputContext(ctx context.Context, arguments map[string]any) error {
if validator == nil || validator.input == nil {
return nil
}
value, err := prepareValidationValue(arguments)
if err != nil {
return err
}
return validateResolved(ctx, validator.validationSlots, validator.input, value)
}View on GitHub (pinned to 9f775e8a12)