When tools fail, and tool inputs are still inputs
Tool calls fail and tool arguments are written by a model. Handle both as you would handle any untrusted input.
Words on this page (7)
- tool use
- : The model asks your program to run a function and reads the result.
- tool
- : A function the model can ask your program to run, described by a name, description and argument schema.
- schema
- : A description of the shape of data: which fields exist and what types they have.
- logarithm
- : The power you raise a base to in order to get a number. log base 2 of 8 is 3 because 2 to the power 3 is 8.
- agent
- : A model run in a loop that chooses its own tools and steps until the task is done.
- prompt
- : The input text you give a model, including instructions, examples and data.
- harness
- : Everything around the model that makes it an agent: prompts, tools, rules, sandboxes, hooks, memory and checks.
Validate arguments
The model produces the arguments. They can be missing, the wrong type or dangerous. Validate against the before running anything. A "search" that builds a SQL string from the argument is an injection hole. Use parameterized queries, allowlists and limits. Treat the model like a user who may be tricked.
Return failures as results
If a tool fails, do not crash the loop. Return an error message as the tool result, written for the model: what failed and what to try. "No results for 'gift cards 2019'. Try a broader query or remove the year." The model can then retry with changes. Cap retries so a persistent failure ends the run with a clear message.
Keep the results honest
Return real data, not guesses, and say when a result is empty or truncated. Pass back any reasoning or tool-call items the provider requires in the next call, since dropping them can degrade behavior or cause an error. each call, its arguments and the result for later review.
Check the data path
Before wiring a tool into an , call it by hand with typical and bad inputs and read what it returns. A tool that works alone but returns a 40,000-token blob will wreck the agent's context.
A worked example: validating
Tool delete_file(path). The model passes "../../etc/passwd". Validation checks that the path stays inside the project folder and refuses with "Path must be inside the project." The model learns the rule and retries with a valid path. The check lives in code, not in the .
Limits on retries
Three attempts is a typical cap. After that, stop and report what was tried. An agent that retries forever burns money.
Three kinds of failure, three messages
Not every problem should be handled the same way.
A bad argument is the model's fault. Return "order_id must be digits only, got '#8123'". The model fixes it and retries.
A broken tool is the world's fault, such as a timeout. Return "The order service timed out. Retrying once may work." The can retry once itself.
An empty result is not a failure at all. Return "No order with id 8123 exists." Retrying will not help. The model should tell the user, not try again.
If all three return the same vague "Error", the model guesses, and often retries the one case that cannot work.
What goes wrong: the silent empty result
A tool catches every exception and returns an empty string. The model reads "nothing came back" as "no order exists" and tells the user their order is missing. The symptom is a confident wrong answer, while the logs show the tool returning empty at the same moment the database was down. Confirm it by switching off the service the tool depends on and reading what the tool returns. It should say it failed.
Check the value, not just the type
A schema can say quantity is an integer, and 1,000,000 is an integer. Types are only the first filter. Add checks on meaning: a refund must not exceed the order total, a date must not be in the past, a path must stay in the project folder. Put these checks in code beside the tool, where the model cannot talk its way around them.
Common mistake
Trusting that arguments will be shaped as described. Models make typos and can be manipulated.
A tool is asked to look up order "ABC" and crashes because order ids are numbers. If the loop crashes too, the user sees nothing. If the tool returns "No order with id ABC. Order ids are numbers like 8123. Ask the customer for the number.", the agent recovers and asks the right question. Good errors turn failures into next steps.
Check yourself
A tool call fails. What should the loop do?
Not quite. The model can recover when the error says what to try.
Why validate tool arguments?
Not quite. Arguments come from a model that may be mistaken or manipulated.
A search tool builds a SQL string from the model's argument. What is the safe change?
Not quite. Treat model output like user input: never build raw queries from it.
You got 0 of 3 right.
Go deeper
- Article
Anthropic · Error messages and responses designed for models.
- Docs
Anthropic · Returning results and errors to the model.
- Article
OWASP · Insecure output and excessive agency risks.
Spotted a mistake or something unclear? Report it on GitHub.