siyuan-note/siyuan · error
structured content is required when an output schema is…
Error message
structured content is required when an output schema is defined
What it means
When a tool declares an OutputSchema, every successful CallToolResult (IsError=false) validated by ValidateOutputContext must carry structured content. This error is thrown if the result has no structured content, because there is nothing to validate against the output schema — the MCP contract requires structuredContent whenever an output schema is defined.
Solutions
- Populate result.StructuredContent with a value matching the tool's OutputSchema in every non-error return path.
- If the tool cannot guarantee structured output, remove the OutputSchema declaration so validation is skipped.
- Audit all return statements in the handler for the structured-content field.
- Add a test that runs the compiled validator's ValidateOutput against representative handler results.
Example fix
// before
return CallToolResult{Content: []ContentItem{{Type: "text", Text: "done"}}}, nil
// after
return CallToolResult{Content: []ContentItem{{Type: "text", Text: "done"}}, StructuredContent: map[string]any{"ok": true}}, nil Defensive patterns
Strategy: validation
Validate before calling
function assertStructured(result) {
if (result.structuredContent === undefined) {
throw new Error("handler returned no structuredContent but OutputSchema is declared");
}
} Type guard
func (r CallToolResult) hasStructured() bool { return r.StructuredContent != nil } Try / catch
if err := validator.ValidateOutput(result); err != nil {
if strings.Contains(err.Error(), "structured content is required") {
// handler bug: populate StructuredContent or drop OutputSchema
}
return err
} Prevention
- Populate StructuredContent in every non-error return path of tools that declare OutputSchema.
- Search handler code paths for early returns that build text-only results.
- Add validator-based tests over representative handler outputs.
- Do not add OutputSchema to legacy text-only tools without updating the handler.
When it happens
Trigger: A tool handler registered with a non-nil OutputSchema returns CallToolResult with only Content (text items) and no StructuredContent field set, and the result passes through ValidateOutputContext (e.g. via handleBrowserCapability or ValidateOutput).
Common situations: Adding an OutputSchema to an existing tool but forgetting to update its handler to populate StructuredContent; a code path returning early with a text-only result; refactoring a handler that used to be text-only into a structured-output tool.
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
- prepare structured content
- attr must be a string or null (got %T)
- each key must be an object
- each key requires name and type
- invalid input schema
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/51b1bdabc89100c6.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/tools/validation.go:127
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)
}
func (validator *ToolValidator) ValidateOutput(result CallToolResult) error {
return validator.ValidateOutputContext(context.Background(), result)
}
func (validator *ToolValidator) ValidateOutputContext(ctx context.Context, result CallToolResult) error {
if validator == nil || validator.output == nil || result.IsError {
return nil
}
if !result.HasStructuredContent() {
return fmt.Errorf("structured content is required when an output schema is defined")
}
value, err := prepareValidationValue(result.StructuredContent)
if err != nil {
return fmt.Errorf("prepare structured content: %w", err)
}
return validateResolved(ctx, validator.validationSlots, validator.output, value)
}
func prepareValidationValue(value any) (any, error) {
if err := validateJSONComplexity(value, maxToolValueDepth, maxToolValueNodes); err != nil {
return nil, err
}
data, err := json.Marshal(value)
if err != nil {
return nil, err
}
if len(data) > maxToolValueBytes {View on GitHub (pinned to 9f775e8a12)