{"record":{"id":"ede93300bff40373","repo":"siyuan-note/siyuan","slug":"capability-validator-unavailable-s","errorCode":null,"errorMessage":"capability validator unavailable: %s","messagePattern":"capability validator unavailable: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/tools.go","lineNumber":67,"sourceCode":"\t}\n\tif err := validator.ValidateInputContext(ctx, args); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid tool arguments: %w\", err)\n\t}\n\treturn t, validator, nil\n}\n\nfunc validateCapabilityCall(ctx context.Context, registration *capabilityRegistration, args map[string]any) error {\n\tif registration == nil {\n\t\treturn fmt.Errorf(\"capability was not exposed in this model round\")\n\t}\n\tif !capabilityStillExecutable(registration, args) {\n\t\treturn fmt.Errorf(\"capability is disabled or no longer available: %s\", registration.ID)\n\t}\n\tif ctx.Err() != nil {\n\t\treturn fmt.Errorf(\"capability execution was cancelled before it started\")\n\t}\n\tif registration.Validator == nil {\n\t\treturn fmt.Errorf(\"capability validator unavailable: %s\", registration.ID)\n\t}\n\tif err := registration.Validator.ValidateInputContext(ctx, args); err != nil {\n\t\treturn fmt.Errorf(\"invalid capability arguments: %w\", err)\n\t}\n\tif !registration.isBrowser() &&\n\t\t(registration.Tool == nil || registration.Tool.ContextHandler == nil && registration.Tool.Handler == nil) {\n\t\treturn fmt.Errorf(\"capability handler unavailable: %s\", registration.ID)\n\t}\n\treturn nil\n}\n\n// executeTool 执行单次工具调用。\nfunc executeTool(ctx context.Context, tc openai.ToolCall, sessionID string) executedToolResult {\n\ttool, validator := tools.LookupToolWithValidator(tc.Function.Name)\n\tif tool == nil {\n\t\treturn executedToolResult{Text: \"unknown tool: \" + tc.Function.Name, IsError: true}\n\t}\n\treturn executeCapability(ctx, tc, sessionID, &capabilityRegistration{","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/agent/tools.go#L49-L85","documentation":"validateCapabilityCall requires every non-trivial registration to carry a Validator (kernel/agent/tools.go:66-68). A nil Validator means the registration was built without the input schema validator that LookupToolWithValidator normally pairs with a tool — an internal invariant break, since arguments could not be validated before execution. The call is refused with the capability ID for diagnosis.","triggerScenarios":"A capabilityRegistration constructed with Validator left nil — only possible from in-kernel code paths (executeTool always sets it from LookupToolWithValidator, tools.go:85-92) or from a future registration builder skipping the validator. Not reachable through any HTTP API input.","commonSituations":"Kernel/plugin developers adding a new registration site and forgetting the validator; refactoring LookupToolWithValidator so it can return a tool without a validator; test harnesses constructing registrations by hand.","solutions":["Find the registration site for the capability ID in the message and set Validator from tools.LookupToolWithValidator","If the capability genuinely needs no schema, provide a permissive validator instead of nil — the invariant is deliberately enforced","Add a unit test asserting every registration in the capability set has a non-nil Validator (see kernel/agent/capability_test.go patterns)","Report it if hit with stock tools — it indicates a version skew or packaging bug"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Registration builders: always pair the tool with its validator\ntool, validator := tools.LookupToolWithValidator(name)\nif tool == nil || validator == nil { /* refuse to register */ }","typeGuard":"null","tryCatchPattern":"if err := validateCapabilityCall(ctx, reg, args); err != nil {\n    if strings.Contains(err.Error(), \"capability validator unavailable\") {\n        // internal invariant break: log capability ID, skip execution, file a bug\n    }\n}","preventionTips":["Assert non-nil Validator in registration tests (pattern in kernel/agent/capability_test.go)","Never construct capabilityRegistration by hand without the validator pair"],"tags":["agent","capability","validator","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}