siyuan-note/siyuan · error
third argument must be a handler function
Error message
third argument must be a handler function
What it means
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.
Source
Thrown at kernel/plugin/api_agent.go:131
if effectsValue := configObj.Get("effects"); isJsValueNotNull(effectsValue) {
if effects, err = jsCapabilityEffectsToGoEffects(rt, effectsValue); err != nil {
return
}
}
if actionEffectsValue := configObj.Get("actionEffects"); isJsValueNotNull(actionEffectsValue) {
if actionEffects, err = jsCapabilityActionEffectsToGoEffects(rt, actionEffectsValue); err != nil {
return
}
}
}
} else {
err = fmt.Errorf("second argument must be a config object")
return
}
if fn, ok := goja.AssertFunction(call.Argument(2)); ok {
handler = fn
} else {
err = fmt.Errorf("third argument must be a handler function")
return
}
return
}
}()
runErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {
if argErr != nil {
err = argErr
return
}
fullToolName := pluginCapabilityModelName(p.Name, name)
declaredActionEffects := make(map[string]tools.ToolEffects, len(actionEffects)+1)
for action, actionEffect := range actionEffects {
declaredActionEffects[action] = actionEffect
}
if effects != nil {View on GitHub (pinned to 251596fc0d)
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
Example fix
// before
await siyuan.agent.registerCapability('myTool', config, 'handleTool');
// after
await siyuan.agent.registerCapability('myTool', config, (args) => {
return { ok: true };
}); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof handler !== 'function') {
throw new TypeError('Handler must be a function');
}
await siyuan.agent.registerCapability(name, config, handler); Type guard
function isCallable(v) {
return typeof v === 'function';
} Prevention
- Pass function references directly, not their names as strings
- Verify handler is a function before calling registerCapability
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- first argument must be a tool name string
- registerCapability requires 3 arguments: name, config, handl
- config.description must not be empty
- config.description is required and must be a string
- config.inputSchema is required
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/6908244c3af3021b.
Report an issue: GitHub.