{"record":{"id":"1979e25f70b41b5c","repo":"siyuan-note/siyuan","slug":"prepare-structured-content-w","errorCode":null,"errorMessage":"prepare structured content: %w","messagePattern":"prepare structured content: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/validation.go","lineNumber":131,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\treturn validateResolved(ctx, validator.validationSlots, validator.input, value)\n}\n\nfunc (validator *ToolValidator) ValidateOutput(result CallToolResult) error {\n\treturn validator.ValidateOutputContext(context.Background(), result)\n}\n\nfunc (validator *ToolValidator) ValidateOutputContext(ctx context.Context, result CallToolResult) error {\n\tif validator == nil || validator.output == nil || result.IsError {\n\t\treturn nil\n\t}\n\tif !result.HasStructuredContent() {\n\t\treturn fmt.Errorf(\"structured content is required when an output schema is defined\")\n\t}\n\tvalue, err := prepareValidationValue(result.StructuredContent)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"prepare structured content: %w\", err)\n\t}\n\treturn validateResolved(ctx, validator.validationSlots, validator.output, value)\n}\n\nfunc prepareValidationValue(value any) (any, error) {\n\tif err := validateJSONComplexity(value, maxToolValueDepth, maxToolValueNodes); err != nil {\n\t\treturn nil, err\n\t}\n\tdata, err := json.Marshal(value)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(data) > maxToolValueBytes {\n\t\treturn nil, fmt.Errorf(\"value exceeds %d bytes\", maxToolValueBytes)\n\t}\n\tvar canonical any\n\tif err = json.Unmarshal(data, &canonical); err != nil {","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/tools/validation.go#L113-L149","documentation":"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: ...'.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nStructuredContent: map[string]any{\"blob\": someChannel} // json.Marshal fails\n// after\nStructuredContent: map[string]any{\"blobId\": blobID} // pass an identifier, keep value JSON-safe","handlingStrategy":"validation","validationCode":"const encoded = JSON.stringify(result.structuredContent);\nif (encoded.length > 8 * 1024 * 1024) throw new Error(\"structured content exceeds 8 MiB\");","typeGuard":"function isJSONSafe(v, seen = new Set()) {\n  if (v === null || [\"string\",\"number\",\"boolean\"].includes(typeof v)) return true;\n  if (typeof v !== \"object\" || seen.has(v)) return false;\n  seen.add(v);\n  return Object.values(v).every(x => isJSONSafe(x, seen));\n}","tryCatchPattern":"if err := validator.ValidateOutputContext(ctx, result); err != nil {\n  var pe *json.UnsupportedTypeError // or inspect wrapped 'prepare structured content' error\n  if strings.HasPrefix(err.Error(), \"prepare structured content:\") {\n    return fmt.Errorf(\"handler emitted non-serializable or oversized output: %w\", err)\n  }\n  return err\n}","preventionTips":["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."],"tags":["mcp","structured-content","validation"],"backgroundTag":"payload-too-large","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}