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

  1. Check the tool name string passed to Handle against the registered constants (ExecToolName, FileToolName) — fix typos or case mismatches
  2. Ensure the tool list advertised to the LLM exactly matches the names Handle dispatches on
  3. 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

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.