{"record":{"id":"6908244c3af3021b","repo":"siyuan-note/siyuan","slug":"third-argument-must-be-a-handler-function","errorCode":null,"errorMessage":"third argument must be a handler function","messagePattern":"third argument must be a handler function","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_agent.go","lineNumber":131,"sourceCode":"\t\t\t\t\t\tif effectsValue := configObj.Get(\"effects\"); isJsValueNotNull(effectsValue) {\n\t\t\t\t\t\t\tif effects, err = jsCapabilityEffectsToGoEffects(rt, effectsValue); err != nil {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif actionEffectsValue := configObj.Get(\"actionEffects\"); isJsValueNotNull(actionEffectsValue) {\n\t\t\t\t\t\t\tif actionEffects, err = jsCapabilityActionEffectsToGoEffects(rt, actionEffectsValue); err != nil {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\terr = fmt.Errorf(\"second argument must be a config object\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif fn, ok := goja.AssertFunction(call.Argument(2)); ok {\n\t\t\t\t\thandler = fn\n\t\t\t\t} else {\n\t\t\t\t\terr = fmt.Errorf(\"third argument must be a handler function\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}()\n\n\t\trunErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {\n\t\t\tif argErr != nil {\n\t\t\t\terr = argErr\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfullToolName := pluginCapabilityModelName(p.Name, name)\n\t\t\tdeclaredActionEffects := make(map[string]tools.ToolEffects, len(actionEffects)+1)\n\t\t\tfor action, actionEffect := range actionEffects {\n\t\t\t\tdeclaredActionEffects[action] = actionEffect\n\t\t\t}\n\t\t\tif effects != nil {","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/plugin/api_agent.go#L113-L149","documentation":"Thrown by siyuan.agent.registerCapability when the third argument fails goja.AssertFunction — the handler is not callable. The handler is stored and later invoked by invokeAgentCapability when the AI model calls the tool, so it must be a JS function.","triggerScenarios":"Passing a non-function as the third argument: registerCapability('myTool', config, 'handler'), registerCapability('myTool', config, {}), or registerCapability('myTool', config, 42). Also fires if the argument is undefined.","commonSituations":"Plugin developer passes a string name of a function instead of the function reference; passes an object with methods instead of a bare function; the handler variable was destructured incorrectly.","solutions":["Pass an actual function reference as the third argument","If using an arrow function or method, ensure you pass the function itself, not its name as a string"],"exampleFix":"// before\nawait siyuan.agent.registerCapability('myTool', config, 'handleTool');\n\n// after\nawait siyuan.agent.registerCapability('myTool', config, (args) => {\n  return { ok: true };\n});","handlingStrategy":"type-guard","validationCode":"if (typeof handler !== 'function') {\n  throw new TypeError('Handler must be a function');\n}\nawait siyuan.agent.registerCapability(name, config, handler);","typeGuard":"function isCallable(v) {\n  return typeof v === 'function';\n}","tryCatchPattern":null,"preventionTips":["Pass function references directly, not their names as strings","Verify handler is a function before calling registerCapability"],"tags":["plugin","agent","capability","type-mismatch","javascript"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}