{"record":{"id":"f35dcd9e242a4f43","repo":"siyuan-note/siyuan","slug":"json-depth-exceeds-d","errorCode":null,"errorMessage":"JSON depth exceeds %d","messagePattern":"JSON depth exceeds (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/validation.go","lineNumber":194,"sourceCode":"\t\t<-validationSlots\n\t\tresult <- err\n\t}()\n\n\tselect {\n\tcase err := <-result:\n\t\treturn err\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-timer.C:\n\t\treturn fmt.Errorf(\"validation exceeded %s\", toolValidationTime)\n\t}\n}\n\nfunc validateJSONComplexity(value any, maxDepth, maxNodes int) error {\n\tnodes := 0\n\tvar walk func(any, int) error\n\twalk = func(current any, depth int) error {\n\t\tif depth > maxDepth {\n\t\t\treturn fmt.Errorf(\"JSON depth exceeds %d\", maxDepth)\n\t\t}\n\t\tnodes++\n\t\tif nodes > maxNodes {\n\t\t\treturn fmt.Errorf(\"JSON node count exceeds %d\", maxNodes)\n\t\t}\n\t\tswitch typed := current.(type) {\n\t\tcase map[string]any:\n\t\t\tfor _, child := range typed {\n\t\t\t\tif err := walk(child, depth+1); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase []any:\n\t\t\tfor _, child := range typed {\n\t\t\t\tif err := walk(child, depth+1); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/tools/validation.go#L176-L212","documentation":"validateJSONComplexity walks an unmarshaled JSON value and rejects it when nesting depth exceeds maxDepth. This guards the kernel's MCP tool layer against deeply nested inputs that could blow the stack or consume excessive memory during schema validation. The depth of the JSON tree is compared per node as the walker recurses.","triggerScenarios":"Any MCP tool call whose JSON argument (tool input schema or parameters) nests maps/arrays/slices deeper than the configured maxDepth when passed to validateJSONComplexity.","commonSituations":"Programmatic clients serializing deeply nested config objects, recursive data structures that accidentally self-reference in JSON generation, or payloads built by wrapping many layers of wrappers/arrays.","solutions":["Flatten the JSON payload so nesting stays within the allowed depth limit","Reduce redundant wrapper layers (e.g. objects with a single child key)","If the limit is genuinely too low for a legitimate use case, raise maxDepth at the call site of validateJSONComplexity","Check the serialized payload with a JSON depth counter before sending"],"exampleFix":"// before\nconst payload = {a:{b:{c:{d:{e:{f:{g:{h:1}}}}}}}} // too deep\n// after\nconst payload = {a_b_c_d_e_f_g_h: 1} // flattened","handlingStrategy":"validation","validationCode":"function jsonDepth(v, d = 0) { if (d > 32) return d; if (Array.isArray(v)) return Math.max(0, ...v.map(x => jsonDepth(x, d + 1))); if (v && typeof v === 'object') return Math.max(0, ...Object.values(v).map(x => jsonDepth(x, d + 1))); return d; }\nif (jsonDepth(payload) > 32) throw new Error('payload nesting too deep');","typeGuard":"const isShallowEnough = (v, max = 32) => jsonDepth(v) <= max;","tryCatchPattern":"null","preventionTips":["Avoid recursive wrapper structures when building tool arguments","Count depth before serializing large config objects","Keep tool input schemas flat; pass references (IDs) instead of nested data"],"tags":["json","validation","mcp","limit"],"backgroundTag":"value-out-of-range","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"}