{"record":{"id":"047bb8bf95e7395e","repo":"siyuan-note/siyuan","slug":"tool-handler-unavailable-s","errorCode":null,"errorMessage":"tool handler unavailable: %s","messagePattern":"tool handler unavailable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/tools.go","lineNumber":45,"sourceCode":"\t\"github.com/siyuan-note/siyuan/kernel/mcp/tools\"\n\tkernelModel \"github.com/siyuan-note/siyuan/kernel/model\"\n)\n\ntype executedToolResult struct {\n\tText             string\n\tModelAttachments []tools.ModelAttachment\n\tIsError          bool\n\tExecutionUnknown bool\n}\n\n// validateToolCallInput 在确认和快照之前校验工具调用，避免无效调用被误判为写操作。\nfunc validateToolCallInput(ctx context.Context, toolName string, args map[string]any) (*tools.Tool, *tools.ToolValidator, error) {\n\tt, validator := tools.LookupToolWithValidator(toolName)\n\tif t == nil {\n\t\treturn nil, nil, fmt.Errorf(\"unknown tool: %s\", toolName)\n\t}\n\tif t.ContextHandler == nil && t.Handler == nil {\n\t\treturn nil, nil, fmt.Errorf(\"tool handler unavailable: %s\", toolName)\n\t}\n\tif ctx.Err() != nil {\n\t\treturn nil, nil, fmt.Errorf(\"tool execution was cancelled before it started\")\n\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 {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/agent/tools.go#L27-L63","documentation":"The tool was found in the registry by name, but both its ContextHandler and Handler fields are nil, so there is no code to execute it. validateToolCallInput refuses to continue because dispatching would panic or silently no-op. This catches registry entries that were registered as placeholders or whose handler wiring failed.","triggerScenarios":"Calling validateToolCallInput with a toolName whose registered tools.Tool struct has ContextHandler == nil && Handler == nil — typically a mis-initialized Tool literal or a tool whose handler was stripped during refactoring.","commonSituations":"A developer adds a tool entry with only metadata (name/description/schema) and forgets to assign Handler; a build-tag or platform-gated file that sets the handler is excluded so the field stays nil; tests construct Tool structs without handlers to exercise this branch.","solutions":["Assign a valid Handler (or ContextHandler) to the tool's tools.Tool definition in the registry.","If the tool is intentionally unimplemented on this platform, remove it from the registry or filter it out of the list exposed to the model.","Add a startup assertion/registration-time check that every registered tool has a handler."],"exampleFix":"// before\nvar writeFile = &tools.Tool{Name: \"writeFile\", Description: \"...\"}\n// after\nvar writeFile = &tools.Tool{Name: \"writeFile\", Description: \"...\", Handler: writeFileHandler}","handlingStrategy":"validation","validationCode":"if t := registry[name]; t != nil && t.Handler == nil && t.ContextHandler == nil {\n    return fmt.Errorf(\"tool %q registered without handler\", name)\n}","typeGuard":null,"tryCatchPattern":"if _, _, err := validateToolCallInput(ctx, name, args); err != nil {\n    if strings.HasPrefix(err.Error(), \"tool handler unavailable:\") { /* fail registration-time, not call-time */ }\n}","preventionTips":["Assign Handler at the same call site where the Tool literal is declared","Add a startup invariant test asserting every registered tool has a handler","Filter platform-gated tools out of the registry when their handler file is excluded"],"tags":["tool-registry","handler","misconfiguration"],"backgroundTag":"method-not-implemented","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}