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
- Check the exact tool name against the registered tool list returned by the tools registry; fix the spelling or use the current registered name.
- If the tool was renamed, update prompts/model schemas so the model only sees current tool names.
- 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
- Generate the model's tool list from the same registry used at dispatch time
- Keep tool names in a shared constant/package to avoid typos
- Log unknown tool names to catch model hallucinations early
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
- image MIME type is missing
- invalid frontend capability ID: %s
- frontend capability description is required: %s
- invalid frontend capability [%s]: %w
- invalid agent permission mode
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/9f439d12b5af2b1f.
Report an issue: GitHub.