siyuan-note/siyuan · error

capability validator unavailable: %s

Error message

capability validator unavailable: %s

What it means

validateCapabilityCall requires every non-trivial registration to carry a Validator (kernel/agent/tools.go:66-68). A nil Validator means the registration was built without the input schema validator that LookupToolWithValidator normally pairs with a tool — an internal invariant break, since arguments could not be validated before execution. The call is refused with the capability ID for diagnosis.

Source

Thrown at kernel/agent/tools.go:67

	}
	if err := validator.ValidateInputContext(ctx, args); err != nil {
		return nil, nil, fmt.Errorf("invalid tool arguments: %w", err)
	}
	return t, validator, nil
}

func validateCapabilityCall(ctx context.Context, registration *capabilityRegistration, args map[string]any) error {
	if registration == nil {
		return fmt.Errorf("capability was not exposed in this model round")
	}
	if !capabilityStillExecutable(registration, args) {
		return fmt.Errorf("capability is disabled or no longer available: %s", registration.ID)
	}
	if ctx.Err() != nil {
		return fmt.Errorf("capability execution was cancelled before it started")
	}
	if registration.Validator == nil {
		return fmt.Errorf("capability validator unavailable: %s", registration.ID)
	}
	if err := registration.Validator.ValidateInputContext(ctx, args); err != nil {
		return fmt.Errorf("invalid capability arguments: %w", err)
	}
	if !registration.isBrowser() &&
		(registration.Tool == nil || registration.Tool.ContextHandler == nil && registration.Tool.Handler == nil) {
		return fmt.Errorf("capability handler unavailable: %s", registration.ID)
	}
	return nil
}

// executeTool 执行单次工具调用。
func executeTool(ctx context.Context, tc openai.ToolCall, sessionID string) executedToolResult {
	tool, validator := tools.LookupToolWithValidator(tc.Function.Name)
	if tool == nil {
		return executedToolResult{Text: "unknown tool: " + tc.Function.Name, IsError: true}
	}
	return executeCapability(ctx, tc, sessionID, &capabilityRegistration{

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Find the registration site for the capability ID in the message and set Validator from tools.LookupToolWithValidator
  2. If the capability genuinely needs no schema, provide a permissive validator instead of nil — the invariant is deliberately enforced
  3. Add a unit test asserting every registration in the capability set has a non-nil Validator (see kernel/agent/capability_test.go patterns)
  4. Report it if hit with stock tools — it indicates a version skew or packaging bug
Defensive patterns

Strategy: try-catch

Validate before calling

// Registration builders: always pair the tool with its validator
tool, validator := tools.LookupToolWithValidator(name)
if tool == nil || validator == nil { /* refuse to register */ }

Type guard

null

Try / catch

if err := validateCapabilityCall(ctx, reg, args); err != nil {
    if strings.Contains(err.Error(), "capability validator unavailable") {
        // internal invariant break: log capability ID, skip execution, file a bug
    }
}

Prevention

When it happens

Trigger: A capabilityRegistration constructed with Validator left nil — only possible from in-kernel code paths (executeTool always sets it from LookupToolWithValidator, tools.go:85-92) or from a future registration builder skipping the validator. Not reachable through any HTTP API input.

Common situations: Kernel/plugin developers adding a new registration site and forgetting the validator; refactoring LookupToolWithValidator so it can return a tool without a validator; test harnesses constructing registrations by hand.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/ede93300bff40373. Report an issue: GitHub.