Home → Help

400 on a tool call — every tool_use needs a matching tool_result

Every tool_use block in an assistant message must be answered by a tool_result block with the same id, in the very next user message, before any other content. Miss one of several, reorder them, or insert text first, and the next request is rejected.

What you are seeing

Why it happens

The conversation is replayed in full on each call, so the API validates the whole structure every time — including turns that were accepted before. That is why the error points at an older message than the one you just sent.

Parallel tool calls are the usual trigger. A model can emit several tool_use blocks in one turn, and handler code written for a single call answers the first and drops the rest.

A failed tool is still a result. Omitting the block because your function threw is exactly the shape the API rejects — return a tool_result carrying the error text instead.

How to fix it

  1. Answer every id, in orderCollect the tool_use ids from the assistant turn, run them, and emit one tool_result per id in the same order at the start of the next user message.
  2. Return errors as resultsWhen a tool throws, send a tool_result with the error message as its content. The model handles that gracefully; a missing block it cannot.
  3. Put text after the resultsIf you want to add a user note in the same turn, place it after all tool_result blocks, never before.
Tool-call traffic is billed as ordinary input and output tokens on APICLAN. A rejected request never runs, so it is not billed — but the retry is, which is why fixing the pairing beats retrying around it.

Related

Unexpected token '<' when calling an OpenAI-compatible API401 invalid API key — when the key looks right but still fails

Last checked 2026-10-01. Written from problems diagnosed on a live OpenAI-compatible gateway, not collected from other sites.