# INVALID_TOOL_RESULTS
## The contract
An AIMessage with `tool_calls` must be followed by exactly one ToolMessage per call, with matching `tool_call_id` values.
## The three violations
- Too few: the model requested two tool calls, you appended one ToolMessage. The model rejects the incomplete chain.
- Too many or duplicates: two ToolMessages for the same tool_call_id, or an id that matches nothing.
- Orphaned: a ToolMessage with no preceding AIMessage containing tool calls.
## Fix
1. Count: `len(tool_calls)` on the AIMessage must equal the number of ToolMessages you append, and every `tool_call_id` must match.
2. If you are building the history by hand (custom agent loop), let LangGraph's ToolNode do this instead; it enforces the pairing for you.
3. In JS this is the INVALID_TOOL_RESULTS error code on `lc_error_code`.
## Rule
Never hand-assemble tool result messages unless you have to. The prebuilt agent loop and ToolNode exist precisely to keep this pairing correct.