When a tool you run fails, still return a tool_result for that call, put the error text in content and set "is_error": true. Claude reads the failure and can retry, try another approach or explain the problem to the user.
How it works
Every tool_use block Claude sends needs a matching tool_result with the same tool_use_id in the next user message. A failure does not change that. If your weather lookup gets an HTTP 500, return {"type": "tool_result", "tool_use_id": "toolu_01...", "content": "ConnectionError: the weather service API is not available (HTTP 500)", "is_error": true}. Claude then works the error into its reply.
Write messages that help Claude recover. A bare failed gives it nothing to act on. Rate limit exceeded. Retry after 60 seconds. says what went wrong and what to do next.
Invalid calls and skipped calls
If Claude calls a tool with a missing or wrong parameter, return the problem as an error result, such as Error: Missing required 'location' parameter. Claude will retry 2 to 3 times with corrections before apologising to the user. To prevent invalid inputs in the first place, set strict: true on the tool.
If Claude sends several calls and you decide not to run one, for example because an earlier call in the batch failed, return a result for it with is_error: true and a brief reason such as Not executed: the preceding write_file call failed. Leaving it out makes the next request fail because a tool_use id has no result.
Server tools are different
is_error is for tools your code runs. Server tools such as web search run on Anthropic's side and report their own failures in the response, with codes such as max_uses_exceeded or query_too_long. Claude handles those itself, and you do not set is_error on them. Your own error handling should cover client tools only.
Where the exam catches people
Believing you can drop the block for a failed call: every tool_use needs a tool_result, or the next request is rejected.
Believing a normal-looking result is harmless when the tool refused: without is_error: true Claude may tell the user the work was done.
Believing a missing argument should abort the run: returning an error result lets Claude correct the call and try again.
Believing server tool errors need is_error from your code: they arrive already described, and Claude handles them.