siyuan-note/siyuan · error

unknown tool

Error message

unknown tool: %s

What it means

validateToolCallInput looks up the requested tool by name with tools.LookupToolWithValidator. If no registered tool matches the name, it returns this error, so unrecognized tool names are rejected before confirmation and snapshot stages.

Solutions

  1. Check the exact registered tool names exposed to the model and correct the caller/model prompt
  2. Ensure the tool's registration function runs before the chat session starts
  3. Log the available tool list when this error occurs to spot typos or case mismatches
  4. If the model hallucinates names, tighten the tool schema/prompt describing available tools

Example fix

// before: assuming the tool exists
validateToolCallInput(ctx, "file_serach", args)
// after: verify against the registry first
if _, ok := tools.Lookup("file_search"); !ok {
    return fmt.Errorf("tool %q is not registered", "file_search")
}
validateToolCallInput(ctx, "file_search", args)
Defensive patterns

Strategy: validation

Validate before calling

if t, _ := tools.LookupToolWithValidator(toolName); t == nil {
    return fmt.Errorf("tool %q not registered; available: %v", toolName, tools.Names())
}

Try / catch

if _, _, err := validateToolCallInput(ctx, name, args); err != nil && strings.HasPrefix(err.Error(), "unknown tool:") {
    return fmt.Errorf("model requested unregistered tool %q; check registry and prompt", name)
}

Prevention

When it happens

Trigger: Calling validateToolCallInput (via the agent chat/tool-call path) with a toolName that is not registered in the tools registry: typo, model hallucinating a tool name, or a tool removed/renamed in a newer version.

Common situations: LLM emits a tool call with a name from an old or imagined schema; plugin/tool not registered because its registration code did not run; case mismatch in tool name.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/9f439d12b5af2b1f. Report an issue: GitHub.

Appendix: source

Thrown at kernel/agent/tools.go:42

	"strings"

	"github.com/sashabaranov/go-openai"
	"github.com/siyuan-note/siyuan/kernel/mcp/tools"
	kernelModel "github.com/siyuan-note/siyuan/kernel/model"
)

type executedToolResult struct {
	Text             string
	ModelAttachments []tools.ModelAttachment
	IsError          bool
	ExecutionUnknown bool
}

// validateToolCallInput 在确认和快照之前校验工具调用,避免无效调用被误判为写操作。
func validateToolCallInput(ctx context.Context, toolName string, args map[string]any) (*tools.Tool, *tools.ToolValidator, error) {
	t, validator := tools.LookupToolWithValidator(toolName)
	if t == nil {
		return nil, nil, fmt.Errorf("unknown tool: %s", toolName)
	}
	if t.ContextHandler == nil && t.Handler == nil {
		return nil, nil, fmt.Errorf("tool handler unavailable: %s", toolName)
	}
	if ctx.Err() != nil {
		return nil, nil, fmt.Errorf("tool execution was cancelled before it started")
	}
	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) {

View on GitHub (pinned to 9f775e8a12)