{"record":{"id":"b6228b0e38013ce7","repo":"siyuan-note/siyuan","slug":"validation-did-not-start-within-s","errorCode":null,"errorMessage":"validation did not start within %s","messagePattern":"validation did not start within (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/mcp/tools/validation.go","lineNumber":170,"sourceCode":"\tif err = validateJSONComplexity(canonical, maxToolValueDepth, maxToolValueNodes); err != nil {\n\t\treturn nil, err\n\t}\n\treturn canonical, nil\n}\n\nfunc validateResolved(ctx context.Context, validationSlots chan struct{}, schema *jsonschema.Resolved, value any) error {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\ttimer := time.NewTimer(toolValidationTime)\n\tdefer timer.Stop()\n\n\tselect {\n\tcase validationSlots <- struct{}{}:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-timer.C:\n\t\treturn fmt.Errorf(\"validation did not start within %s\", toolValidationTime)\n\t}\n\n\tresult := make(chan error, 1)\n\tgo func() {\n\t\terr := schema.Validate(value)\n\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}","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/tools/validation.go#L152-L188","documentation":"validateResolved gates schema validation behind a semaphore of toolValidationConcurrency=4 slots and a 2-second (toolValidationTime) acquisition deadline. If no slot frees up within 2 seconds — because four other validations are concurrently holding slots on slow, pathological payloads — the validation is abandoned with this timeout rather than queued indefinitely.","triggerScenarios":"More than 4 concurrent tool calls whose input/output validation is in progress, each taking long enough (large payloads near the 8 MiB / 262144-node limits) that a fifth waits over 2 seconds for a slot; typically under heavy parallel MCP traffic.","commonSituations":"Load/stress tests firing many simultaneous tool calls; a slow or adversarial payload monopolizing validation slots; saturated CPU on the host slowing jsonschema.Validate for all in-flight calls.","solutions":["Retry the tool call; the condition is usually transient under load.","Reduce concurrent tool invocations from the client (serialize or batch fewer calls).","Shrink argument/output payload sizes so each validation completes faster and slots free quickly.","Increase toolValidationConcurrency or toolValidationTime in validation.go if sustained parallelism is a legitimate workload."],"exampleFix":"// before\n// client fires 32 tool calls in parallel; 5th+ wait > 2s\nawait Promise.all(ids.map(callTool))\n// after\n// limit in-flight calls to below the 4-slot validation concurrency\nawait pLimit(4, ids.map(callTool))","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := validator.ValidateInputContext(ctx, args)\nif errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), \"validation did not start within\") {\n  // transient slot starvation: back off and retry once\n  time.Sleep(250 * time.Millisecond)\n  err = validator.ValidateInputContext(ctx, args)\n}","preventionTips":["Limit concurrent in-flight tool calls to roughly the validation concurrency (4).","Keep argument payloads small so validations complete quickly and free slots.","Add client-side backoff/retry on this timeout — it is transient under load.","Monitor validation latency; persistently hitting the 2s budget means lowering parallelism or raising limits."],"tags":["timeout","concurrency","mcp","validation"],"backgroundTag":"request-timeout","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"}