siyuan-note/siyuan · error

invalid frontend capability ID: %s

Error message

invalid frontend capability ID: %s

What it means

capability.go validates each frontend capability id with validFrontendCapabilityID(). The id must be exactly 'native/frontend/<name>' (3 segments) or 'plugin/frontend/<owner>/<name>' (4 segments), with no empty segments and total length <= 512. Any other shape returns the formatted error naming the offending id.

Source

Thrown at kernel/agent/capability.go:216

			Description:   tool.Description,
			Source:        source,
			OwnerID:       tool.OwnerID,
			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"

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Format ids strictly as 'native/frontend/<name>' or 'plugin/frontend/<owner>/<name>' with non-empty owner/name.
  2. Validate the id client-side with the same segment rule before sending it to the kernel.
  3. Trim owner/name and reject empty values at registration time in the frontend (Plugin.addAgentCapability already does encodeURIComponent — supply non-empty raw values).
  4. Keep the total id length under 512 characters.

Example fix

// before
id := fmt.Sprintf('plugin/frontend/%s/', owner) // empty name segment
// after
if owner == '' || name == '' { return errors.New('owner and name required') }
id := fmt.Sprintf('plugin/frontend/%s/%s', owner, name)
Defensive patterns

Strategy: validation

Validate before calling

func validID(id string) bool {
    if len(id) > 512 { return false }
    p := strings.Split(id, '/')
    return (len(p) == 3 && p[0]=='native' && p[1]=='frontend' && p[2] != '') ||
        (len(p) == 4 && p[0]=='plugin' && p[1]=='frontend' && p[2] != '' && p[3] != '')
}

Try / catch

if err := buildCapabilitySet(...); err != nil {
    if strings.Contains(err.Error(), 'invalid frontend capability ID') { /* log offending id, skip */ }
    return err
}

Prevention

When it happens

Trigger: A frontend capability is registered with an id missing a segment (e.g. 'plugin/frontend/' with empty owner or name), using a wrong prefix ('frontend/x/y'), extra slashes, a >512 char id, or a name that URI-decodes to empty.

Common situations: Plugin uses encodeURIComponent on an already-encoded name producing extra slashes; capability id constructed from user input that was blank; refactor changed the prefix constant; URIDecode on the server yields an empty trailing segment.

Related errors


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