[ERROR] You did not use a tool in your previous response! Please retry with a tool use
No API rejected anything here. The request succeeded, the model answered, and
your agent harness then decided the answer was unusable because it contained no
tool call. This string is written by that harness and injected back into the
conversation as a new turn — it is not an Anthropic error, not an OpenAI error,
and it will not appear in any provider’s error reference. So rule out the whole
class you would normally check: it is not your key, not your quota, not a
malformed request body, and not a 400. Nothing about your request was invalid.
What failed is an expectation your client enforces, and the model has no way
of knowing it exists except by being told.
Who is enforcing this, and why they have to
An agent loop advances on tool calls. The harness sends the conversation, reads the reply, executes whatever the reply asked for, appends the result, and sends again. A reply with no tool call gives the loop nothing to execute and nothing to append, so the loop either stops or invents a turn. This message is the invented turn: a synthetic user message that says the previous response was unusable, appended so the loop can send once more.
The enforcement is strictest in harnesses that do not use the provider’s native tool-use API. Those define their tools in the system prompt as a text or XML format and parse the calls back out of plain prose. That design buys portability across providers, and it pays for it here: when tools live in the prompt, there is no structural guarantee that an answer contains one. The protocol is an instruction, and instructions are followed probabilistically. With a native tool-use API, the same requirement can be expressed as a constraint on the request, where a prose-only answer is not a thing the model can return.
That difference is the first thing to establish about your own setup, because the entire fix branches on it.
Is retrying useful?
No — the retry is the message. You are being shown the result of one.
The harness already re-sent the conversation with this reminder appended; what you are looking at is either that attempt or the one after it. Sending the same thing again is a third sample against inputs that are now slightly worse than the ones that failed, for the reason in the next section.
There is a cost to letting it spin, too. Every attempt replays the whole conversation as input tokens, and a failed or rejected request still counts against your per-minute rate limit — OpenAI’s documentation states this outright. A loop that retries this forever is one that converts your quota into nothing at a steady rate. If you have wrapped your own retry around the agent loop, put a cap on consecutive tool-less turns and stop there.
The correct move after seeing it twice is to change one thing — the protocol, the tool surface, or the history — and then run once.
Why it gets worse the longer it runs
This is the part that explains the behavior everyone reports: the loop does not just fail once, it settles into failing.
The reminder is appended to the conversation, and so is the tool-less assistant turn that provoked it. Every future request therefore carries an in-context example of an assistant turn that answered in prose. Models pattern-match on their own transcript. A history containing three examples of prose-only answers is a history that makes a fourth prose-only answer more likely, no matter how firmly the system prompt forbids it. The correction is self-reinforcing in the wrong direction.
The practical consequence: once you are two or three of these deep, the history itself is a cause and not just a record. Cutting the failed exchanges out — rewinding, or restarting the task from a clean context — is more effective than any further instruction, and it is the step people skip because the transcript looks like evidence rather than like an input.
Telling the four causes apart
- The tool syntax is actually in the raw response. Check this first, because it is the only cause that is not about model behavior at all. Look at the unrendered response body, not the chat UI. If the call is there and the harness still complained, you have a parser or placement bug: the call was emitted inside a reasoning or thinking segment that gets stripped before parsing, or wrapped in a code fence the parser does not accept, or the closing tag is missing by one character. Fix the protocol handling, not the prompt.
- The model asked you a question, or said it was finished. Read the prose it produced. If it is a clarifying question or a summary of completed work, the model wanted to do something the protocol has no slot for. That is a gap in your tool surface, not disobedience.
- It happens on one model and not another. Swap the model, keep everything else, and run the same task. A text-parsed tool protocol depends entirely on instruction-following, and that varies enormously across model families and sizes. A protocol that works on a flagship model and collapses on a small or older one is diagnostic, not anecdotal.
- It only happens deep into a task. Early turns are fine, later ones drift. That is the accumulation described above, usually compounded by a system prompt that has been pushed far from the end of the context by tool output.
Fix by cause
- Parser or placement bug — handle reasoning content explicitly rather than discarding it, and accept the fenced form of your tool syntax. One reproduction with a logged raw response settles it in minutes; without the raw response you will spend an afternoon rewriting prompts that were never wrong.
- Missing slot in the tool surface — give the model a tool for every legal intention. If there is no tool that means “ask the user a question” and no tool that means “the task is done”, then prose is the model’s only way to do either of those things, and it will keep reaching for it. This is the highest value change on the list, because it removes the reason rather than raising the penalty.
- Model-dependent failure — move to the provider’s native tool-use API if the harness supports it, and constrain the request so a call is required. Making the empty answer unrepresentable beats asking for it not to happen. If you must stay on a text protocol, keep the format shallow: one call per turn, flat parameters, no nesting.
- Drift late in a task — break the task into shorter runs and restart context between them. Re-stating the protocol just before the end of the conversation helps more than strengthening it at the top, because position matters more than emphasis.
- What not to do — rewriting the system prompt in capitals. The instruction is already there; the failure is in the tail of a distribution, and shouting moves the average rather than the tail. If a stern paragraph were sufficient, the harness would not have needed to write this message in the first place.
Confirming it is fixed
“It got past that turn” is not a confirmation, because any single turn can succeed by chance, and the tool-less answer was always a minority outcome to begin with.
Run the same task end to end, twice, on the same model, and count tool-less turns rather than watching for the string. Zero across two full runs is a fix; one occurrence that the harness silently recovered from is the same bug at a lower rate, and it will come back in a longer task. If the change you made was switching to a native, constrained tool-use call, the confirmation is stronger and available immediately: the failure mode becomes structurally impossible, so a single clean run proves the class is gone rather than that this instance passed.
Related errors
If the model did emit a call and the client could not read it, you are on a different page: a tool call that could not be parsed, where the retry also failed is a malformed call rather than a missing one, and the constants that cause it are in the tool schema. If the loop broke mid-batch and your later requests started failing regardless of what you type, the tool-use concurrency 400 that points at /rewind describes damaged history, which is a harder problem than a wasted turn. And if one call in a batch failed while the others came back as a sibling-tool-call placeholder, the placeholder is not the diagnosis and the tool may have run anyway. The AI coding error triage tool separates the ones your client wrote from the ones a provider returned — which, on this page, is the distinction that sends you to the right file to edit.