{"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":"exception","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/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/tools/validation.go#L152-L188","documentation":"Thrown by validateResolved when the bounded validation semaphore (validationSlots, capacity toolValidationConcurrency=4) could not be acquired within toolValidationTime (2s). All 4 concurrent validation slots were occupied for the full window, so this validation could not even start. It is a back-pressure/fairness guard, not a verdict on the value being validated.","triggerScenarios":"Four other schema.Validate calls are already running (each potentially slow) and a fifth validation waits the full 2s without obtaining a slot; the context has not been cancelled in the meantime.","commonSituations":"A burst of many tool calls under load (e.g., an agent fan-out) saturates the 4-slot pool; one or more schemas are pathologically slow to validate (deep $ref graphs, expensive patterns) and hog slots; running on a CPU-throttled host where validation is slow.","solutions":["Reduce concurrency of tool invocations or batch them so fewer validations run simultaneously.","Simplify the schemas (fewer/cheaper regex patterns, shallower $ref chains) so each schema.Validate completes faster and frees its slot.","Pass a context with a longer deadline if the caller can tolerate waiting, and ensure the caller does not cancel prematurely.","If sustained load is expected, consider whether per-tool pre-compilation can eliminate runtime validation entirely."],"exampleFix":"// before: fire 50 tool calls concurrently, saturating the 4-slot pool\nfor _, t := range tools { go call(t) }\n// after: bound concurrency to leave headroom\nsem := make(chan struct{}, 4)\nfor _, t := range tools { sem <- struct{}{}; go func(t){ defer func(){<-sem}(); call(t) }(t) }","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := validator.ValidateInputContext(ctx, args)\nif err != nil && strings.Contains(err.Error(), \"validation did not start\") {\n    // back off and retry once; otherwise propagate\n}","preventionTips":["Bound the concurrency of tool calls you issue in parallel to leave validation slots free.","Simplify schemas so each validation finishes quickly and frees its slot.","Pass a context deadline sized to tolerate the 2s start window under load."],"tags":["mcp","validation","concurrency","timeout","backpressure"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}