BerriAI/litellm · error · Exception
Missing corresponding tool call for tool response message. R
Error message
Missing corresponding tool call for tool response message. Received - message={message}, last_message_with_tool_calls={last_message_with_tool_calls} What it means
Raised when converting a role='tool' message for Gemini: LiteLLM looks up the function name by matching message.tool_call_id against the tool_calls in the last assistant message with tool calls, and no match with a non-empty name was found. Gemini needs the function name on every functionResponse, so an unmatched tool result cannot be forwarded.
Source
Thrown at litellm/litellm_core_utils/prompt_templates/factory.py:1497
if last_message_with_tool_calls:
tools: Final = last_message_with_tool_calls.get("tool_calls", [])
msg_tool_call_id: Final = message.get("tool_call_id", None)
for tool in tools:
prev_tool_call_id = tool.get("id", None)
if msg_tool_call_id and prev_tool_call_id and msg_tool_call_id == prev_tool_call_id:
name = tool.get("function", {}).get("name", "")
# Echo the OpenAI tool_call_id on functionResponse (strip thought-signature suffix).
gemini_call_id: str | None = None
if forward_function_call_id:
raw_tool_call_id: Final = message.get("tool_call_id")
if raw_tool_call_id and isinstance(raw_tool_call_id, str):
stripped_id: Final = raw_tool_call_id.split(THOUGHT_SIGNATURE_SEPARATOR, 1)[0]
if stripped_id:
gemini_call_id = stripped_id
if not name:
raise Exception(
f"Missing corresponding tool call for tool response message. Received - message={message}, last_message_with_tool_calls={last_message_with_tool_calls}"
)
# Parse response data - support both JSON string and plain string
# For Computer Use, the response should contain structured data like {"url": "..."}
response_data: dict
try:
if content_str.strip().startswith("{") or content_str.strip().startswith("["):
# Try to parse as JSON (for Computer Use structured responses)
parsed: Final = json.loads(content_str)
if isinstance(parsed, dict):
response_data = parsed # Use the parsed JSON directly
else:
response_data = {"content": content_str}
else:
response_data = {"content": content_str}
except (json.JSONDecodeError, ValueError):
# Not valid JSON, wrap in content fieldView on GitHub (pinned to 6c2dcb801b)
Solutions
- Ensure the assistant message containing the matching tool_calls (with ids) is present immediately before the tool result in messages
- Echo back the exact tool_call_id from the assistant message on the tool response
- When trimming history, never cut between an assistant tool_calls turn and its tool responses
- For parallel calls, keep every tool response, one per tool_call_id, before the next user turn
Example fix
# before
messages = [
{"role": "user", "content": "Weather?"},
{"role": "tool", "tool_call_id": "call_1", "content": "72F"}, # assistant tool_calls turn was trimmed
]
# after
messages = [
{"role": "user", "content": "Weather?"},
{"role": "assistant", "tool_calls": [{"id": "call_1", "type": "function",
"function": {"name": "get_weather", "arguments": "{\"city\": \"SF\"}"}}]},
{"role": "tool", "tool_call_id": "call_1", "content": "72F"},
] Defensive patterns
Strategy: validation
Validate before calling
def tool_results_match(messages) -> bool:
last_ids = None
for m in messages:
if m.get("role") == "assistant" and m.get("tool_calls"):
last_ids = {tc.get("id") for tc in m["tool_calls"]}
elif m.get("role") == "tool":
if not last_ids or m.get("tool_call_id") not in last_ids:
return False
return True
assert tool_results_match(messages), "tool result without matching assistant tool_call" Prevention
- Echo tool_call_id exactly from the assistant tool_call
- Keep assistant tool_calls turns adjacent to their tool responses when trimming history
- One tool response per tool_call_id, all before the next user turn
When it happens
Trigger: Sending a tool message whose tool_call_id doesn't match any id in the preceding assistant tool_calls (typos, regenerated ids, stripped thought-signature suffix mismatch); sending the tool response without the assistant tool-call message in between; empty tool_calls in the referenced assistant message.
Common situations: Multi-turn agent loops where history is trimmed and the assistant tool-call turn falls out of the window; parallel tool calls where results are matched by index instead of id; providers that mutate tool_call ids; replaying stored conversations after id sanitization.
Related errors
- function_call missing. Received tool call with 'type': 'func
- Unable to convert openai tool calls={message} to gemini tool
- Failed to parse tool call arguments. Error: {original_error}
- function_call missing. Received tool call with 'type': 'func
- Unable to parse anthropic tool result for message: {message}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/95e226d8a343e45e.
Report an issue: GitHub.