siyuan-note/siyuan · error
prepare structured content: %w
Error message
prepare structured content: %w
What it means
Wraps any error returned by prepareValidationValue while preparing the structured content of a tool result for output-schema validation. The underlying cause is almost always a JSON-complexity limit (depth/nodes/bytes exceeded, see errors 364/367/368) or a json.Marshal/Unmarshal failure on the StructuredContent value. The %w verb preserves the wrapped error for inspection with errors.Is/errors.As.
Source
Thrown at kernel/mcp/tools/validation.go:132
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 {
return nil, fmt.Errorf("value exceeds %d bytes", maxToolValueBytes)
}
var canonical any
if err = json.Unmarshal(data, &canonical); err != nil {
return nil, errView on GitHub (pinned to 251596fc0d)
Solutions
- Inspect the wrapped error with errors.Unwrap/errors.As to identify whether it is a size, depth, node-count, or marshal error, then address that specific limit.
- Ensure StructuredContent is a plain JSON-serializable value (map[string]any, slices of primitives, structs with JSON tags).
- Trim or paginate large outputs so the marshaled size stays under 8 MiB and depth under 128.
- Unit-test the handler's StructuredContent by marshaling it through encoding/json before wiring it to the tool.
Example fix
// before: handler stores a non-serializable value
result.StructuredContent = someLiveObjectWithChannels
// after
result.StructuredContent = map[string]any{"id": obj.ID, "name": obj.Name} Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := json.Marshal(structuredContent); err != nil { return fmt.Errorf("structured content not serializable: %w", err) } Try / catch
err := validator.ValidateOutputContext(ctx, result)
if err != nil {
if inner := errors.Unwrap(err); inner != nil { /* inspect complexity/marshal cause */ }
// degrade: return text content only, or convert to IsError result
} Prevention
- Only store JSON-serializable values (maps, slices, primitives, tagged structs) in StructuredContent.
- Unit-test marshaling each handler's structured output before wiring it to a tool.
- Keep structured outputs within the depth/node/byte budgets (128 / 262144 / 8 MiB).
When it happens
Trigger: ValidateOutputContext calls prepareValidationValue(result.StructuredContent); that value fails validateJSONComplexity, exceeds maxToolValueBytes (8 MiB), or contains a type that json.Marshal cannot encode (e.g., a channel, func, or cyclic struct).
Common situations: A tool returns a deeply nested or very large structured object; a handler stores a non-JSON-serializable Go value (chan, func, unsafe.Pointer, or a struct with unexported fields and no marshaler) into StructuredContent; a handler accidentally embeds the entire request or a live pointer graph.
Related errors
- structured content is required when an output schema is defi
- tools/list returned an empty response
- tools/list repeated cursor %q
- unsupported server type: %s
- command is required for stdio server
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/1979e25f70b41b5c.
Report an issue: GitHub.