{"record":{"id":"73e25d476072de8c","repo":"siyuan-note/siyuan","slug":"second-argument-must-be-a-function","errorCode":null,"errorMessage":"second argument must be a function","messagePattern":"second argument must be a function","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_rpc.go","lineNumber":60,"sourceCode":"\t\tvar name string\n\t\tvar method goja.Callable\n\t\tvar descriptions []string\n\t\tif len(call.Arguments) < 2 {\n\t\t\targErr = fmt.Errorf(\"method name and function required\")\n\t\t} else {\n\t\t\tnameArg := call.Argument(0)\n\t\t\tmethodArg := call.Argument(1)\n\t\t\tdescArgs := call.Arguments[2:]\n\t\t\tif goja.IsString(nameArg) {\n\t\t\t\tname = nameArg.String()\n\t\t\t} else {\n\t\t\t\targErr = fmt.Errorf(\"first argument must be method name string\")\n\t\t\t}\n\t\t\tif argErr == nil {\n\t\t\t\tif methodJs, ok := goja.AssertFunction(methodArg); ok {\n\t\t\t\t\tmethod = methodJs\n\t\t\t\t} else {\n\t\t\t\t\targErr = fmt.Errorf(\"second argument must be a function\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tif argErr == nil {\n\t\t\t\tdescriptions = make([]string, len(descArgs))\n\t\t\t\tfor i, a := range descArgs {\n\t\t\t\t\tdescriptions[i] = a.String()\n\t\t\t\t}\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\t\t\terr = p.bindRpcMethod(name, method, descriptions...)\n\t\t\treturn\n\t\t}, func(rt *goja.Runtime, result any, err error) {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/api_rpc.go#L42-L78","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nsiyuan.rpc.bind('myMethod', handlers['myMethod']) // handlers['myMethod'] is undefined\n// after\nsiyuan.rpc.bind('myMethod', (params) => { return { ok: true } })","handlingStrategy":"type-guard","validationCode":"if (typeof handler !== 'function') { throw new TypeError('rpc bind handler must be a function') }\nsiyuan.rpc.bind('myMethod', handler)","typeGuard":"const isFn = (v) => typeof v === 'function'","tryCatchPattern":null,"preventionTips":["Always pass inline function expressions to bind calls","Check typeof before binding dynamically selected handlers","Avoid invoking the handler accidentally (handler() vs handler)"],"tags":["javascript","rpc","argument-type"],"backgroundTag":"invalid-argument-value","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}