shareAI-lab/learn-claude-code · error · GoalError

unknown tool '{name}'

Error message

unknown tool '{name}'

What it means

AgentSession._run_tool dispatched a tool name that matches none of the implemented tools (bash, read, write, edit, glob, ...), so it raises GoalError(f"unknown tool '{name}'") at s17_goal_loop/code.py:807. The tool registry is a closed set of if-branches; any other name falls through to this error.

Source

Thrown at s17_goal_loop/code.py:807

            path = self._safe_path(str(arguments["path"]))
            old_text = str(arguments["old_text"])
            new_text = str(arguments["new_text"])
            content = path.read_text(encoding="utf-8")
            count = content.count(old_text)
            if count != 1:
                return f"Error: Expected 1 occurrence, found {count}"
            path.write_text(content.replace(old_text, new_text), encoding="utf-8")
            return f"Edited {path.relative_to(self.workdir)}"

        if name == "glob":
            matches = [
                match
                for match in glob.glob(str(arguments["pattern"]), root_dir=self.workdir)
                if (self.workdir / match).resolve().is_relative_to(self.workdir)
            ]
            return "\n".join(matches[:200]) if matches else "(no matches)"

        raise GoalError(f"unknown tool '{name}'")


def make_live_session(workdir: Path) -> AgentSession:
    try:
        from anthropic import Anthropic
        from dotenv import load_dotenv
    except ImportError as error:
        raise GoalError(
            "Install dependencies first: pip install -r requirements.txt"
        ) from error

    load_dotenv(override=True)
    model = os.getenv("MODEL_ID")
    if not model:
        raise GoalError("MODEL_ID is required in the environment or .env")
    evaluator_model = (
        os.getenv("GOAL_EVALUATOR_MODEL_ID")
        or os.getenv("ANTHROPIC_DEFAULT_HAIKU_MODEL")

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Align the tool definitions passed to the model with the branches in _run_tool (same names, no extras)
  2. If the model hallucinates, strengthen the tool descriptions/system prompt so only defined tools are used
  3. Wrap the session loop in try/except GoalError and retry; a retry usually corrects the tool choice
  4. Add a matching branch (or an alias) in _run_tool if the tool is genuinely wanted

Example fix

# before
# tool sent to model includes {"name": "list_dir", ...} but _run_query has no branch for it

# after
# either rename the definition to the implemented tool:
tools = [{"name": "glob", "description": "list files matching a pattern", ...}]
Defensive patterns

Strategy: retry

Validate before calling

IMPLEMENTED_TOOLS = {"bash", "read", "write", "edit", "glob"}
tools = [t for t in advertised_tools if t["name"] in IMPLEMENTED_TOOLS]
assert len(tools) == len(advertised_tools), "tool list diverges from dispatcher"

Type guard

def is_known_tool(name: object) -> bool:
    return isinstance(name, str) and name in {"bash", "read", "write", "edit", "glob"}

Try / catch

try:
    await session.submit(query)
except GoalError as error:
    if "unknown tool" in str(error):
        result = await session.submit(query)  # retry; model self-corrects on replay
    else:
        raise

Prevention

When it happens

Trigger: The model emits a tool_use block with a name like 'grep', 'list_files', or a hallucinated tool not in the session's tool list; tools advertised to the model diverge from the ones implemented in _run_tool; a newer client sends a tool name this older code does not know.

Common situations: Tool schema sent to the model includes tools that were later renamed or removed from _run_tool; model hallucinating a tool name mid-run; version skew between the tool definitions and the dispatcher after an edit.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/40bfc26ac4055491. Report an issue: GitHub.