siyuan-note/siyuan · error

registerCapability requires 3 arguments: name, config…

Error message

registerCapability requires 3 arguments: name, config, handler

What it means

registerCapability() is the plugin API for registering an agent tool/capability with the kernel. It requires exactly three arguments: a name string, a config object, and a handler function. The runtime throws this error before doing any work when fewer than three arguments are passed, because a capability cannot be registered without all three pieces.

Solutions

  1. Pass all three arguments in order: registerCapability(name, config, handler)
  2. Define the handler function and the config object before the call site
  3. Log typeof each argument (string, object, function) before calling to spot the missing one

Example fix

// before
plugin.registerCapability("my_tool", { description: "..." });
// after
plugin.registerCapability("my_tool", { description: "...", inputSchema: {...} }, async (args) => { return { content: "ok" }; });
Defensive patterns

Strategy: validation

Validate before calling

function canRegister(args) { return Array.isArray(args) && args.length >= 3; }
if (!canRegister([name, config, handler])) throw new Error("registerCapability needs (name, config, handler)");

Type guard

const isRegisterable = (n, c, h) => typeof n === "string" && n.trim() !== "" && c !== null && typeof c === "object" && typeof h === "function";

Try / catch

try { plugin.registerCapability(name, config, handler); } catch (e) { if (String(e).includes("registerCapability requires 3 arguments")) { /* fix arg count */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling registerCapability(name, config) with only two arguments, registerCapability(name) with one, or registerCapability() with none — e.g. omitting the handler callback or forgetting the config object in the call.

Common situations: Copy-pasted plugin sample code where the handler was trimmed; refactoring that removed the config argument; dynamically-built argument lists where an optional value ended up undefined; typos in a wrapper function that forwards arguments incorrectly.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/ab43c454dc19fb87. Report an issue: GitHub.

Appendix: source

Thrown at kernel/plugin/api_agent.go:70

	agentAPI := rt.NewObject()

	// siyuan.agent.registerCapability(name, config, handler) 返回 Promise<IRegisteredCapability>。
	lo.Must0(agentAPI.Set("registerCapability", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
		promise, resolve, reject := rt.NewPromise()

		var name string
		var title string
		var description string
		var effects *tools.ToolEffects
		var actionEffects map[string]tools.ToolEffects
		var inputSchema *tools.ToolSchema
		var outputSchema *tools.ToolSchema
		var handler goja.Callable

		argErr := func() (err error) {
			if len(call.Arguments) < 3 {
				err = fmt.Errorf("registerCapability requires 3 arguments: name, config, handler")
				return
			} else {
				if s := call.Argument(0); goja.IsString(s) {
					name = strings.TrimSpace(s.String())
					if name == "" {
						err = fmt.Errorf("capability name must not be empty")
						return
					}
				} else {
					err = fmt.Errorf("first argument must be a tool name string")
					return
				}

				if c := call.Argument(1); isJsValueNotNull(c) {
					configObj := c.ToObject(rt)
					if configObj != nil {
						if titleValue := configObj.Get("title"); goja.IsString(titleValue) {
							title = titleValue.String()

View on GitHub (pinned to 9f775e8a12)