vxcontrol/pentagi · error
unknown tool: %s
Error message
unknown tool: %s
What it means
Handle dispatches a tool call by its name; the outer switch only knows ExecToolName and FileToolName. If the LLM or caller supplies any other tool name, the terminal wrapper returns "unknown tool: %s" naming the unrecognized tool. It is a dispatch-level guard, not a runtime failure.
Source
Thrown at backend/pkg/tools/terminal.go:186
"path": action.Path,
})
switch action.Action {
case ReadFile:
result, err := t.ReadFile(ctx, t.flowID, action.Path.String())
return t.wrapCommandResult(ctx, args, name, result, err)
case WriteFile:
result, err := t.WriteFile(ctx, t.flowID, action.Content, action.Path.String())
return t.wrapCommandResult(ctx, args, name, result, err)
case EditFile:
result, err := t.EditFile(ctx, t.flowID, action.Path.String(), action.Diff.String())
return t.wrapCommandResult(ctx, args, name, result, err)
default:
logger.Error("unknown file action")
return "", fmt.Errorf("unknown file action: %s", action.Action)
}
default:
return "", fmt.Errorf("unknown tool: %s", name)
}
}
func (t *terminal) ExecCommand(
ctx context.Context,
cwd, command string,
detach bool,
timeout time.Duration,
) (string, error) {
containerName := PrimaryTerminalName(t.tenantPrefix, t.flowID)
cmd := []string{
"sh",
"-c",
command,
}
isRunning, err := t.dockerClient.IsContainerRunning(ctx, t.containerLID)View on GitHub (pinned to ea665308ba)
Solutions
- Check the tool name string passed to Handle against the registered constants (ExecToolName, FileToolName) — fix typos or case mismatches
- Ensure the tool list advertised to the LLM exactly matches the names Handle dispatches on
- Add the missing case to the switch if the tool is legitimately new
Example fix
// before result, err := terminal.Handle(ctx, "shell", args) // unknown tool: shell // after result, err := terminal.Handle(ctx, tools.ExecToolName, args)
Defensive patterns
Strategy: validation
Validate before calling
func validateToolName(name string) error {
switch name {
case tools.ExecToolName, tools.FileToolName:
return nil
default:
return fmt.Errorf("unsupported tool %q; must be %q or %q", name, tools.ExecToolName, tools.FileToolName)
}
}
if err := validateToolName(name); err != nil { return err } Type guard
func isKnownTool(name string) bool {
return name == tools.ExecToolName || name == tools.FileToolName
} Try / catch
result, err := terminal.Handle(ctx, name, args)
if err != nil {
if strings.HasPrefix(err.Error(), "unknown tool:") {
// fall back to a known tool or report schema mismatch to the orchestrator
return handleUnknownTool(ctx, name, args)
}
return err
} Prevention
- Always reference tool-name constants instead of raw string literals
- Keep the tool schema advertised to the LLM generated from the same constants Handle dispatches on
- Log the full args payload on unknown-tool errors to catch hallucinated names early
When it happens
Trigger: Calling terminal.Handle with a name other than "exec" or "file" — e.g. a typo in the tool name registered with the LLM, a stale tool registry, or the LLM hallucinating a tool name like "shell" or "read_file".
Common situations: Prompt/tool schema mismatch after renaming a tool; an agent model inventing a tool not in the registered list; wiring the same handler into a provider whose tool list was updated independently.
Related errors
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/b921ef13e5fec40a.
Report an issue: GitHub.