{"record":{"id":"dd6ad746b9caf708","repo":"siyuan-note/siyuan","slug":"frontend-capability-description-is-required-s","errorCode":null,"errorMessage":"frontend capability description is required: %s","messagePattern":"frontend capability description is required: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/capability.go","lineNumber":219,"sourceCode":"\t\t\tOwnerName:     tool.OwnerName,\n\t\t\tRuntime:       runtime,\n\t\t\tTool:          tool,\n\t\t\tValidator:     validator,\n\t\t\tInputSchema:   tool.InputSchema,\n\t\t\tOutputSchema:  tool.OutputSchema,\n\t\t\tAccessContext: accessContext,\n\t\t}\n\t\tif err := set.add(registration); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tfor _, frontend := range frontendCapabilities {\n\t\tif !validFrontendCapabilityID(frontend.ID) {\n\t\t\treturn nil, fmt.Errorf(\"invalid frontend capability ID: %s\", frontend.ID)\n\t\t}\n\t\tif strings.TrimSpace(frontend.Description) == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"frontend capability description is required: %s\", frontend.ID)\n\t\t}\n\t\tif !capabilityAllowed(frontend.ID, accessContext) {\n\t\t\tcontinue\n\t\t}\n\t\tvalidationTool := &tools.Tool{\n\t\t\tName:         frontendCapabilityModelName(frontend.ID),\n\t\t\tDescription:  frontend.Description,\n\t\t\tInputSchema:  frontend.InputSchema,\n\t\t\tOutputSchema: frontend.OutputSchema,\n\t\t}\n\t\tvalidator, err := tools.CompileToolValidator(validationTool)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid frontend capability [%s]: %w\", frontend.ID, err)\n\t\t}\n\t\tsource := \"native\"\n\t\tif strings.HasPrefix(frontend.ID, \"plugin/frontend/\") {\n\t\t\tsource = \"plugin\"\n\t\t}","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/agent/capability.go#L201-L237","documentation":"capability.go checks strings.TrimSpace(frontend.Description) == '' right after the id check and returns this formatted error. Even with a valid id, a capability whose description is blank (or only whitespace) is rejected because the description is what the model reads to decide when to call the capability.","triggerScenarios":"A frontend capability is sent with description '', description consisting of only spaces/tabs, or a description field that was supposed to be localized but resolved to empty.","commonSituations":"Plugin registers a capability with description pulled from an i18n key that was not yet translated; refactor removed the description; JSON marshal omitted the field so it defaults to empty; the description was set from a runtime variable that evaluated to ''.","solutions":["Always supply a non-empty, meaningful description (it is shown to the model).","Trim and assert non-empty at the frontend registration site before posting to the kernel.","If i18n lookup fails, fall back to a hardcoded English description rather than empty.","Validate the capability payload (id + description) with a shared schema on both sides."],"exampleFix":"// before\ncap := FrontendCapability{ID: id, Description: ''}\n// after\ndesc := strings.TrimSpace(localizedDesc)\nif desc == '' { desc = 'Default capability description' }\ncap := FrontendCapability{ID: id, Description: desc}","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(frontend.Description) == '' { frontend.Description = 'Default capability description' }","typeGuard":null,"tryCatchPattern":"if err := buildCapabilitySet(...); err != nil {\n    if strings.Contains(err.Error(), 'description is required') { /* set fallback and retry */ }\n    return err\n}","preventionTips":["Always supply a non-empty description; it is shown to the model.","Fall back to a hardcoded English string if i18n lookup returns empty.","Validate description non-empty at the registration site before posting.","Share a capability-payload validator between frontend and kernel."],"tags":["agent","capability","validation","go"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}