siyuan-note/siyuan · error
second argument must be a function
Error message
second argument must be a function
What it means
The siyuan.rpc.bind-style binding API in kernel/plugin/api_rpc.go requires the second call argument to be a JavaScript function (the method implementation). goja.AssertFunction failed, so the kernel rejects the bind call with this error instead of registering the method. It protects the RPC registry from storing a non-callable handler.
Solutions
- Pass an actual function as the second argument to the bind call
- Log typeof the second argument before binding to confirm it is 'function'
- Check that imported handler symbols exist (no undefined imports)
- If wrapping an async function, ensure the wrapper itself is a function expression, not the result of invoking it
Example fix
// before
siyuan.rpc.bind('myMethod', handlers['myMethod']) // handlers['myMethod'] is undefined
// after
siyuan.rpc.bind('myMethod', (params) => { return { ok: true } }) Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof handler !== 'function') { throw new TypeError('rpc bind handler must be a function') }
siyuan.rpc.bind('myMethod', handler) Type guard
const isFn = (v) => typeof v === 'function'
Prevention
- Always pass inline function expressions to bind calls
- Check typeof before binding dynamically selected handlers
- Avoid invoking the handler accidentally (handler() vs handler)
When it happens
Trigger: Calling the plugin RPC bind API with the method implementation argument missing, undefined, or passed as a non-function (e.g. a string, object, or arrow function stored in a variable that is undefined at bind time).
Common situations: Typos in the handler variable name; destructuring a module export that does not exist; passing an async wrapper object instead of a function; refactoring that renamed the handler but not the bind call.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- method name required
- method required
- failed to enable extend modules
- failed to inject global context
- first argument must be method name string
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/73e25d476072de8c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/plugin/api_rpc.go:60
var name string
var method goja.Callable
var descriptions []string
if len(call.Arguments) < 2 {
argErr = fmt.Errorf("method name and function required")
} else {
nameArg := call.Argument(0)
methodArg := call.Argument(1)
descArgs := call.Arguments[2:]
if goja.IsString(nameArg) {
name = nameArg.String()
} else {
argErr = fmt.Errorf("first argument must be method name string")
}
if argErr == nil {
if methodJs, ok := goja.AssertFunction(methodArg); ok {
method = methodJs
} else {
argErr = fmt.Errorf("second argument must be a function")
}
}
if argErr == nil {
descriptions = make([]string, len(descArgs))
for i, a := range descArgs {
descriptions[i] = a.String()
}
}
}
runErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {
if argErr != nil {
err = argErr
return
}
err = p.bindRpcMethod(name, method, descriptions...)
return
}, func(rt *goja.Runtime, result any, err error) {View on GitHub (pinned to 9f775e8a12)