siyuan-note/siyuan · error

unknown tool: %s

Error message

unknown tool: %s

What it means

validateToolCallInput rejects a tool call whose toolName does not exist in the registered tool registry. tools.LookupToolWithValidator returns nil for any name that was never registered, so the agent cannot resolve a handler or validator and fails fast before treating the call as a write operation. This guards the confirmation/snapshot pipeline from invoking nonexistent tools.

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 8641553a1f)

Solutions

  1. Check the exact tool name against the registered tool list returned by the tools registry; fix the spelling or use the current registered name.
  2. If the tool was renamed, update prompts/model schemas so the model only sees current tool names.
  3. Ensure the tool is actually registered before tool calls are dispatched (registration ordering at agent startup).

Example fix

// before
validateToolCallInput(ctx, "file_writ", args)
// after
validateToolCallInput(ctx, "writeFile", args) // exact registered tool name
Defensive patterns

Strategy: validation

Validate before calling

if _, ok := registeredTools[toolName]; !ok {
    return fmt.Errorf("tool %q is not registered", toolName)
}

Try / catch

if _, _, err := validateToolCallInput(ctx, name, args); err != nil {
    if strings.HasPrefix(err.Error(), "unknown tool:") { /* re-prompt model with valid tool list */ }
}

Prevention

When it happens

Trigger: Calling validateToolCallInput (directly in tests like TestValidateToolCallInputRejectsMissingActionBeforeConfirmation, or via executeTool processing an LLM tool_call) with a toolName string that is not present in the tools registry — e.g. a typo, a renamed tool, or a model hallucinating a tool name.

Common situations: The model emits a tool name from an older tool schema after the registry was renamed; a test passes a fictional tool name; plugin/capability code registers tools under different identifiers than the ones the model was told about.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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