{"record":{"id":"378051521a50f79a","repo":"siyuan-note/siyuan","slug":"capability-name-must-not-be-empty","errorCode":null,"errorMessage":"capability name must not be empty","messagePattern":"capability name must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_agent.go","lineNumber":76,"sourceCode":"\n\t\tvar name string\n\t\tvar title string\n\t\tvar description string\n\t\tvar effects *tools.ToolEffects\n\t\tvar actionEffects map[string]tools.ToolEffects\n\t\tvar inputSchema *tools.ToolSchema\n\t\tvar outputSchema *tools.ToolSchema\n\t\tvar handler goja.Callable\n\n\t\targErr := func() (err error) {\n\t\t\tif len(call.Arguments) < 3 {\n\t\t\t\terr = fmt.Errorf(\"registerCapability requires 3 arguments: name, config, handler\")\n\t\t\t\treturn\n\t\t\t} else {\n\t\t\t\tif s := call.Argument(0); goja.IsString(s) {\n\t\t\t\t\tname = strings.TrimSpace(s.String())\n\t\t\t\t\tif name == \"\" {\n\t\t\t\t\t\terr = fmt.Errorf(\"capability name must not be empty\")\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\terr = fmt.Errorf(\"first argument must be a tool name string\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif c := call.Argument(1); isJsValueNotNull(c) {\n\t\t\t\t\tconfigObj := c.ToObject(rt)\n\t\t\t\t\tif configObj != nil {\n\t\t\t\t\t\tif titleValue := configObj.Get(\"title\"); goja.IsString(titleValue) {\n\t\t\t\t\t\t\ttitle = titleValue.String()\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif descriptionValue := configObj.Get(\"description\"); goja.IsString(descriptionValue) {\n\t\t\t\t\t\t\tdescription = strings.TrimSpace(descriptionValue.String())\n\t\t\t\t\t\t\tif description == \"\" {\n\t\t\t\t\t\t\t\terr = fmt.Errorf(\"config.description must not be empty\")\n\t\t\t\t\t\t\t\treturn","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/api_agent.go#L58-L94","documentation":"The first argument to registerCapability() was a string, but after trimming whitespace it was empty. Every capability must have a non-empty name so the kernel can key it, expose it to the agent, and allow later unregistration by name.","triggerScenarios":"registerCapability(\"\", config, handler), registerCapability(\"   \", config, handler), or passing a variable that resolves to an empty string (e.g. an unset constant or an object lookup that returned \"\").","commonSituations":"Template placeholders like registerCapability(TOOL_NAME, ...) where TOOL_NAME was never set; config-driven registration where the tool name field is empty; building names via concatenation where a prefix/suffix variable is blank.","solutions":["Provide a non-empty, trimmed name string as the first argument","Check the variable feeding the name for empty/whitespace-only values before registering","Use a stable, descriptive identifier (e.g. \"myplugin_search_notes\")"],"exampleFix":"// before\nconst name = \"   \";\nplugin.registerCapability(name, config, handler);\n// after\nconst name = \"myplugin_search_notes\";\nif (name.trim()) plugin.registerCapability(name, config, handler);","handlingStrategy":"validation","validationCode":"if (typeof name === \"string\" && name.trim() === \"\") { throw new Error(\"capability name is empty\"); }","typeGuard":"const hasValidName = (n) => typeof n === \"string\" && n.trim().length > 0;","tryCatchPattern":"try { plugin.registerCapability(name, config, handler); } catch (e) { if (String(e).includes(\"name must not be empty\")) { name = fallbackName; return plugin.registerCapability(name, config, handler); } throw e; }","preventionTips":["Never rely on unset constants for the tool name","Trim and check names before registration","Use plugin-id-prefixed names to guarantee uniqueness"],"tags":["plugin-api","empty-string","agent-capability"],"backgroundTag":"empty-required-field","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"}