An agent calls your tool and gets back Error: invalid request. It has no information about what was invalid, so it does the only thing available: tries again, identically. Gets the same error. Tries a third time with a small random variation. Burns budget, achieves nothing, and eventually gives up or hits a step cap.
The tool worked correctly. The error message was written for a developer reading a log file, and it is being read by a model that has to decide what to do next.
What changed in 2026
- Tool error text got recognised as prompt surface. Teams started treating error strings with the same care as tool descriptions rather than as logging output.
- Structured errors spread. Returning a machine-readable error type alongside human-readable text let agents branch reliably.
- Retry storms became visible. Cost attribution made repeated identical failing calls show up as a line item.
- MCP and similar protocols standardised the shape. Consistent error conventions across tool servers reduced per-tool handling.
What a useful error contains
| Element |
Why the model needs it |
| What went wrong |
To know the call failed at all |
| Which input was at fault |
To know what to change |
| What would be valid |
To know what to change it to |
| Whether retrying could help |
To avoid a retry loop |
| What to try instead |
To make progress rather than stop |
Compare two responses to the same failure:
"Error: invalid request" — the model knows nothing.
"Unknown status 'pending_review'. Valid values: open, closed, archived. Retrying with the same value will fail." — the model can correct the call immediately, and knows not to retry blindly.
The second costs a few more tokens and saves several failed calls. On any agent doing repeated tool work, that trade is overwhelmingly favourable.
Listing valid options is the single highest-value addition. A rejected enum value with the allowed set attached converts a dead end into a one-step correction.
Retryable versus permanent
The distinction the model cannot infer and must be told.
Retryable: rate limits, timeouts, transient service errors, temporary lock contention. Waiting and retrying may succeed.
Permanent: malformed input, invalid values, missing permissions, a resource that does not exist. Retrying identically will fail identically, forever.
An agent that cannot distinguish them defaults to retrying, which is correct for the first category and pure waste for the second. Saying so explicitly in the error text — or better, in a structured field — removes the guesswork.
Rate limits deserve a specific note: include how long to wait. An agent told to retry without a duration will retry immediately, which makes the rate limit worse. The same reasoning as thundering herd, applied to one agent.
Never fail silently
The worst error handling is none. A tool that catches its own exception and returns an empty result, a default value, or null produces the most damaging outcome available: the agent believes it succeeded.
It then reasons from a wrong fact, builds on it, and produces a confident conclusion with no indication anything went wrong. This is exactly the mechanism of context poisoning, and it is self-inflicted.
An empty search result meaning "no matches" and an empty search result meaning "the search service is down" must be distinguishable. If they are not, the agent will conclude the corpus contains nothing on the topic and proceed accordingly.
The rule: return an error when something failed, always, even when returning something plausible would be easier.
Common mistakes
- Generic error text. Nothing to act on.
- Stack traces. Context consumed, no signal.
- Silent defaults on failure. The agent believes a lie.
- No retryable indication. Retry loops on permanent failures.
- Rate limits without a wait duration. Immediate retry worsens it.
- Rejecting a value without listing valid ones. Turns a correction into a guess.
- Inconsistent error shapes across tools. The agent cannot learn one convention.
FAQ
Should errors be structured or prose?
Both. A structured type lets your code branch reliably; prose lets the model understand. Returning a type field plus a clear sentence covers both consumers.
How verbose should they be?
Long enough to be actionable, short enough not to dominate context. A sentence or two with the specific offending value and the valid alternatives is usually right.
What about errors containing sensitive data?
Redact before returning. Error paths are a common leak route, and an error string with a customer identifier in it is now in the model context and your traces — see PII redaction for LLMs.
Should the agent see every error?
Not necessarily. Transient failures your code already retried successfully need not reach the model at all. Surface what the agent should act on.
Where to go next
For designing the tools these errors come from, read tool schema design. For the contamination silent failures cause, context poisoning, and for bounding retry loops, agent token budgets.