{"record":{"id":"ff5f057428a4ae12","repo":"siyuan-note/siyuan","slug":"capability-handler-unavailable-s","errorCode":null,"errorMessage":"capability handler unavailable: %s","messagePattern":"capability handler unavailable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/tools.go","lineNumber":74,"sourceCode":"func 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{\n\t\tID:        tools.CapabilityIDForTool(tool),\n\t\tModelName: tool.Name,\n\t\tSource:    tool.Source,\n\t\tRuntime:   tool.Runtime,\n\t\tTool:      tool,\n\t\tValidator: validator,\n\t})","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/agent/tools.go#L56-L92","documentation":"The last validation in validateCapabilityCall (kernel/agent/tools.go:72-75): a non-browser capability must have a Tool whose ContextHandler or Handler is set. Browser capabilities (Runtime == \"browser\") are exempt because their handlers live in the frontend and calls are dispatched back over SSE. Failing this check means the registration points at a backend tool with no executable function — an internal registration bug, not a user input problem.","triggerScenarios":"A backend capabilityRegistration built with Tool == nil or with a tools.Tool that defines neither Handler nor ContextHandler — e.g. a tool registered for its schema/effects only, a refactor removing a handler without pruning the registration, or a native tool declaration misclassified as non-browser. Browser-capability paths (handleBrowserCapability) never hit it.","commonSituations":"Kernel/plugin development: declaring a tool's schema for prompt-building but wiring no handler; copy-paste registrations; version skew where a tool struct lost its handler in a refactor.","solutions":["Look up the capability ID in the message, find its registration, and set Tool.ContextHandler or Tool.Handler","If the capability is frontend-hosted, ensure Runtime is exactly \"browser\" (isBrowser check, capability.go:109-111) so it takes the SSE dispatch path","Assert in tests that every registered non-browser tool has a handler (pattern in kernel/agent/capability_test.go)","If hit with unmodified stock tools, report the capability ID — it marks a packaging/version defect"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Registration builders: require a handler for backend tools\nif !reg.isBrowser() && (reg.Tool == nil || (reg.Tool.ContextHandler == nil && reg.Tool.Handler == nil)) {\n    // refuse registration\n}","typeGuard":"null","tryCatchPattern":"if err := validateCapabilityCall(ctx, reg, args); err != nil {\n    if strings.Contains(err.Error(), \"capability handler unavailable\") {\n        // internal defect: log capability ID and drop the registration\n    }\n}","preventionTips":["Set Runtime \"browser\" only for frontend-hosted capabilities (SSE dispatch), never to mask a missing backend handler","Test that every registered non-browser tool executes in CI"],"tags":["agent","capability","handler","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}