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

  1. Pass an actual function as the second argument to the bind call
  2. Log typeof the second argument before binding to confirm it is 'function'
  3. Check that imported handler symbols exist (no undefined imports)
  4. 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

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


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)