siyuan-note/siyuan · error

frontend capability description is required: %s

Error message

frontend capability description is required: %s

What it means

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.

Source

Thrown at kernel/agent/capability.go:219

			OwnerName:     tool.OwnerName,
			Runtime:       runtime,
			Tool:          tool,
			Validator:     validator,
			InputSchema:   tool.InputSchema,
			OutputSchema:  tool.OutputSchema,
			AccessContext: accessContext,
		}
		if err := set.add(registration); err != nil {
			return nil, err
		}
	}

	for _, frontend := range frontendCapabilities {
		if !validFrontendCapabilityID(frontend.ID) {
			return nil, fmt.Errorf("invalid frontend capability ID: %s", frontend.ID)
		}
		if strings.TrimSpace(frontend.Description) == "" {
			return nil, fmt.Errorf("frontend capability description is required: %s", frontend.ID)
		}
		if !capabilityAllowed(frontend.ID, accessContext) {
			continue
		}
		validationTool := &tools.Tool{
			Name:         frontendCapabilityModelName(frontend.ID),
			Description:  frontend.Description,
			InputSchema:  frontend.InputSchema,
			OutputSchema: frontend.OutputSchema,
		}
		validator, err := tools.CompileToolValidator(validationTool)
		if err != nil {
			return nil, fmt.Errorf("invalid frontend capability [%s]: %w", frontend.ID, err)
		}
		source := "native"
		if strings.HasPrefix(frontend.ID, "plugin/frontend/") {
			source = "plugin"
		}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Always supply a non-empty, meaningful description (it is shown to the model).
  2. Trim and assert non-empty at the frontend registration site before posting to the kernel.
  3. If i18n lookup fails, fall back to a hardcoded English description rather than empty.
  4. Validate the capability payload (id + description) with a shared schema on both sides.

Example fix

// before
cap := FrontendCapability{ID: id, Description: ''}
// after
desc := strings.TrimSpace(localizedDesc)
if desc == '' { desc = 'Default capability description' }
cap := FrontendCapability{ID: id, Description: desc}
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(frontend.Description) == '' { frontend.Description = 'Default capability description' }

Try / catch

if err := buildCapabilitySet(...); err != nil {
    if strings.Contains(err.Error(), 'description is required') { /* set fallback and retry */ }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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 ''.

Related errors


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