Last month my agent confidently called a tool named search_invoices. That tool did not exist. It never existed. The model invented the name, invented the arguments, and emitted a perfectly-formed JSON block for it. My harness, trusting and naive, tried to dispatch it and crashed.
If you build agents, you've seen this. The model calls a tool that isn't in your schema, or it calls a real tool with arguments that don't match the input schema, or it narrates a tool call in plain text instead of emitting the actual tool_use block. People call all of this "hallucinating tool calls." I want to explain why it happens at the mechanism level, because once you see it, the fixes stop feeling like superstition.
The model is predicting tokens, not running your code
Here's the thing nobody tells you when you start. A tool call is not a function invocation from the model's side. It's text. Structured text, sure, but text. The model emits a tool_use block the same way it emits a paragraph: by predicting the most likely next tokens given everything before. Your schema is part of that context, but it's not a hard constraint unless you make it one.
So when does it go wrong? When the distribution of plausible next tokens points somewhere your schema doesn't. If your conversation history is full of references to invoices, and the model decides it needs invoice data, search_invoices is a wildly plausible token sequence — even if the tool you gave it is actually called query_billing. The model is pattern-matching against everything it's ever seen, and "search_" + noun is one of the most common tool-name shapes in its training data.
This is why hallucinated tool calls spike in two situations: when your tool names are unusual, and when your context is long and noisy.
Fix one: make the right call the most probable call
Name your tools the way the model expects tools to be named. get_weather, send_email, search_database. Boring is good. Boring is predictable, and predictable means the model's next-token guess lands on your actual tool instead of an invented cousin.
Then write descriptions that say when to call, not just what the tool does. This matters more on recent Claude models — Opus 4.7 and 4.8 reach for tools more conservatively than 4.6 did, so a description like "Call this when the user asks about current prices or recent events" measurably raises the should-call rate. The trigger condition is part of what the model conditions on. Put it in the description, not buried in the system prompt.
Fix two: stop letting bad calls through
When the model does emit a malformed call, your harness should reject it loudly, not crash. Return a tool_result with is_error: true and a message the model can read:
{
"type": "tool_result",
"tool_use_id": "toolu_abc",
"content": "No tool named 'search_invoices'. Available: query_billing, get_customer.",
"is_error": true
}
The model reads that error on the next turn and corrects. I've watched Opus 4.8 recover from a hallucinated tool name in a single turn this way — it sees the error, looks at the available list, and re-emits the right call. Don't drop the failed call silently. Don't retry the same prompt and hope. Feed the error back.
Fix three: strict schemas for the argument problem
The name hallucination and the argument hallucination are different bugs. For arguments — wrong types, missing required fields, extra fields — use strict tool use. Set strict: true on the tool definition itself (not on tool_choice, that does nothing), with additionalProperties: false and a required list. Now the API guarantees the input validates against your schema exactly. The model literally cannot emit an argument shape that doesn't fit.
One caveat: strict mode isn't compatible with everything. It won't work with programmatic tool calling, forced tool_choice, or MCP tools. For those you're back to validating yourself.
Fix four: shorten the context the call depends on
Remember the long-and-noisy trigger? In a long agentic loop, old tool results pile up. By turn 40 the model is conditioning on 39 turns of mostly-irrelevant output, and the signal for "which tool, which args" gets drowned. This is where context editing earns its keep — clearing stale tool_use results so the model's next prediction is based on what's actually relevant. It's a beta feature (clear_tool_uses_20250919), and it's not the same as compaction, which summarizes instead of clearing. For tool-call accuracy specifically, clearing beats summarizing, because a summary of old tool output still nudges the distribution.
The one that surprises people
When the model narrates a tool call instead of emitting it — "I'll now search the database for that" with no actual tool_use block — that's not really a hallucination. That's the model ending its turn early. On long Claude runs it occasionally writes a statement of intent without the call. The fix is a system-prompt nudge: tell it that before ending a turn, if its last paragraph is a promise about work it hasn't done, it should do that work now with a tool call. A plain "continue" recovers it interactively. For autonomous pipelines, bake the instruction in.
What I want you to take away is this: none of these fixes are magic. They all do the same thing — bend the probability distribution toward the call you want, or catch the call you don't. The model isn't malfunctioning when it invents search_invoices. It's doing exactly what it was built to do, with a context that pointed the wrong way. Point it better.
