siyuan-note/siyuan · error
prepare structured content
Error message
prepare structured content: %w
What it means
ValidateOutputContext normalizes the result's StructuredContent via prepareValidationValue before schema validation (JSON round-trip for canonicalization plus complexity checks). If that preparation fails — unmarshalable value, size over maxToolValueBytes (8 MiB), or depth/node limits (128 depth, 262144 nodes) — the error is wrapped as 'prepare structured content: ...'.
Solutions
- Read the wrapped inner error: json marshal error, byte limit, or complexity limit — fix accordingly.
- Ensure StructuredContent only contains JSON-safe types (maps, slices, strings, numbers, bools, nil).
- Trim or reference (e.g. by asset path) large payloads instead of embedding them in structured content.
- Flatten deep nesting in the handler's output value.
Example fix
// before
StructuredContent: map[string]any{"blob": someChannel} // json.Marshal fails
// after
StructuredContent: map[string]any{"blobId": blobID} // pass an identifier, keep value JSON-safe Defensive patterns
Strategy: validation
Validate before calling
const encoded = JSON.stringify(result.structuredContent);
if (encoded.length > 8 * 1024 * 1024) throw new Error("structured content exceeds 8 MiB"); Type guard
function isJSONSafe(v, seen = new Set()) {
if (v === null || ["string","number","boolean"].includes(typeof v)) return true;
if (typeof v !== "object" || seen.has(v)) return false;
seen.add(v);
return Object.values(v).every(x => isJSONSafe(x, seen));
} Try / catch
if err := validator.ValidateOutputContext(ctx, result); err != nil {
var pe *json.UnsupportedTypeError // or inspect wrapped 'prepare structured content' error
if strings.HasPrefix(err.Error(), "prepare structured content:") {
return fmt.Errorf("handler emitted non-serializable or oversized output: %w", err)
}
return err
} Prevention
- Restrict StructuredContent to JSON-safe types; never embed channels, funcs, or cyclic references.
- Summarize or paginate large results instead of embedding full payloads.
- Keep nesting shallow — depth 128 / 262144 node budgets apply.
- Round-trip test output values through json.Marshal/Unmarshal in handler tests.
When it happens
Trigger: A tool result's StructuredContent contains values json.Marshal cannot encode (channels, funcs, cyclic maps), exceeds 8 MiB serialized, or nests deeper than 128 levels / has more than 262144 nodes.
Common situations: Returning Go structs with unsupported field types in StructuredContent; accidentally including huge blobs (base64 file contents) in structured output; deeply recursive data structures produced by the handler.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- structured content is required when an output schema is…
- 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/1979e25f70b41b5c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/tools/validation.go:131
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 {
return nil, fmt.Errorf("value exceeds %d bytes", maxToolValueBytes)
}
var canonical any
if err = json.Unmarshal(data, &canonical); err != nil {View on GitHub (pinned to 9f775e8a12)