siyuan-note/siyuan · warning
validation exceeded
Error message
validation exceeded %s
What it means
Once a validation slot is acquired, validateResolved runs jsonschema.Validate in a goroutine and waits up to toolValidationTime (2 seconds) for it to finish. If validation does not complete within 2 seconds — pathological payloads near the size/complexity limits on a slow host — the wait is abandoned with this timeout and the validation result is discarded.
Solutions
- Retry with a smaller, simpler payload; split large arguments into multiple calls.
- Reduce nesting and node count of the value being validated.
- Simplify the tool's schema (fewer patternProperties/regex constraints) so validation is cheaper.
- Raise toolValidationTime in validation.go only if legitimate payloads genuinely need longer.
Example fix
// before validateResolved(ctx, slots, schema, deeplyNested8MBValue) // Validate > 2s // after validateResolved(ctx, slots, schema, summarizedValue) // flattened, paginated value validates well under 2s
Defensive patterns
Strategy: retry
Validate before calling
const depth = v => typeof v === "object" && v !== null ? 1 + Math.max(0, ...Object.values(v).map(depth)) : 0;
if (depth(payload) > 100) throw new Error("payload too deeply nested for fast validation"); Try / catch
if err := validator.ValidateOutput(result); err != nil {
if strings.Contains(err.Error(), "validation exceeded") {
// simplify payload or retry with a smaller value
return retryWithTruncatedPayload(result)
}
return err
} Prevention
- Keep validated values small and shallow — near-limit payloads (8 MiB / 262144 nodes) risk the 2s budget.
- Avoid regex-heavy schema keywords over long strings in tool schemas.
- Reduce host CPU contention; validation runs on a shared 4-slot pool.
- Tune toolValidationTime only after profiling legitimate worst-case payloads.
When it happens
Trigger: Validating an input or structured-output value whose complexity (up to 128 depth / 262144 nodes) makes jsonschema.Validate exceed 2 seconds; heavily loaded CPU; an adversarial payload crafted to stress the validator (billion-laughs-style nesting within limits).
Common situations: Stress tests with maximal-size payloads; production hosts under CPU starvation validating many large tool payloads; regex-heavy schema keywords evaluated against long strings.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- validation did not start within
- Argon2id Iterations too high (maximum 10)
- attr must be a string or null (got %T)
- connect
- each key must be an object
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/343d1745488164f9.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/tools/validation.go:186
return ctx.Err()
case <-timer.C:
return fmt.Errorf("validation did not start within %s", toolValidationTime)
}
result := make(chan error, 1)
go func() {
err := schema.Validate(value)
<-validationSlots
result <- err
}()
select {
case err := <-result:
return err
case <-ctx.Done():
return ctx.Err()
case <-timer.C:
return fmt.Errorf("validation exceeded %s", toolValidationTime)
}
}
func validateJSONComplexity(value any, maxDepth, maxNodes int) error {
nodes := 0
var walk func(any, int) error
walk = func(current any, depth int) error {
if depth > maxDepth {
return fmt.Errorf("JSON depth exceeds %d", maxDepth)
}
nodes++
if nodes > maxNodes {
return fmt.Errorf("JSON node count exceeds %d", maxNodes)
}
switch typed := current.(type) {
case map[string]any:
for _, child := range typed {
if err := walk(child, depth+1); err != nil {View on GitHub (pinned to 9f775e8a12)