siyuan-note/siyuan · error

method name required

Error message

method name required

What it means

Thrown by siyuan.rpc.unbind() when the plugin calls it with zero arguments. unbind deregisters an RPC method previously registered via siyuan.rpc.bind(name, fn). It requires the method name so the kernel knows which handler to remove; with no argument there is nothing to remove and the call is rejected before any worker work runs.

Source

Thrown at kernel/plugin/api_rpc.go:105

			}
		})
		if runErr != nil {
			logging.LogErrorf("[plugin:%s] siyuan.rpc.bind worker run: %v", p.Name, runErr)
			if rejectErr := reject(rt.NewGoError(runErr)); rejectErr != nil {
				logging.LogErrorf("[plugin:%s] siyuan.rpc.bind reject: %v", p.Name, rejectErr)
			}
		}

		return rt.ToValue(promise)
	})))

	lo.Must0(rpc.Set("unbind", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
		promise, resolve, reject := rt.NewPromise()

		var argErr error
		var name string
		if len(call.Arguments) < 1 {
			argErr = fmt.Errorf("method name required")
		} else if nameArg := call.Argument(0); goja.IsString(nameArg) {
			name = nameArg.String()
		} else {
			argErr = fmt.Errorf("first argument must be method name string")
		}

		runErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {
			if argErr != nil {
				err = argErr
				return
			}
			err = p.unbindRpcMethod(name)
			return
		}, func(rt *goja.Runtime, result any, err error) {
			if lo.IsNil(err) {
				if resolveErr := resolve(result); resolveErr != nil {
					logging.LogErrorf("[plugin:%s] siyuan.rpc.unbind resolve: %v", p.Name, resolveErr)
				}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Pass the method name string that was used in the matching siyuan.rpc.bind(name, fn) call.
  2. If you are iterating over a list of names, guard for empty arrays before calling unbind.
  3. Keep bind/unbind name constants in a single shared module so they never drift out of sync.

Example fix

// before
await siyuan.rpc.unbind();
// after
await siyuan.rpc.unbind('myPlugin.myMethod');
Defensive patterns

Strategy: validation

Validate before calling

function assertUnbindArgs(name) {
  if (typeof name !== 'string' || name.length === 0) {
    throw new TypeError('unbind requires a non-empty method name string');
  }
}
// assertUnbindArgs(name); await siyuan.rpc.unbind(name);

Type guard

const isMethodName = (v) => typeof v === 'string' && v.length > 0;

Try / catch

try {
  await siyuan.rpc.unbind(name);
} catch (e) {
  if (/method name required/.test(String(e))) { /* name missing: log and skip */ }
  else { throw e; }
}

Prevention

When it happens

Trigger: Calling await siyuan.rpc.unbind() with no arguments, or calling unbind.apply(undefined, []) / Reflect.apply with an empty args array.

Common situations: Plugin code that conditionally unbinds a method but forgets to pass the name (e.g. unbind() instead of unbind('myMethod')), or refactor leftovers where a variable holding the name was removed but the call kept its empty parentheses.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/23e6655fbe556796. Report an issue: GitHub.