zylon-ai/private-gpt · error · ValueError
Expected tool calls in response but found none. Message: {re
Error message
Expected tool calls in response but found none. Message: {response.message} What it means
ValueError raised while extracting tool calls from an OpenAI Responses LLM result when no ToolCallBlock is present in message.blocks nor in additional_kwargs['tool_calls'], and error_on_no_tool_call is enabled. It means the model answered with plain content instead of invoking a function/tool, and the caller declared that a tool call was mandatory.
Source
Thrown at private_gpt/components/llm/custom/openairesponses.py:224
never accumulates blocks — it stores ToolCallBlock objects in
message.additional_kwargs["tool_calls"] instead. We check both locations.
"""
from llama_index.core.llms.llm import ToolSelection
from llama_index.core.llms.utils import parse_partial_json
# Non-streaming / ResponseCompletedEvent path: blocks populated directly
tool_call_blocks = [
b for b in response.message.blocks if isinstance(b, ToolCallBlock)
]
# Streaming accumulation path: _handle_stream_chunk stores them here
if not tool_call_blocks:
raw = response.message.additional_kwargs.get("tool_calls", [])
tool_call_blocks = [tc for tc in raw if isinstance(tc, ToolCallBlock)]
if not tool_call_blocks:
if error_on_no_tool_call:
raise ValueError(
"Expected tool calls in response but found none. "
f"Message: {response.message}"
)
return []
tool_selections = []
for b in tool_call_blocks:
# tool_kwargs may be a JSON string (Responses API) or already a dict
raw_kwargs = b.tool_kwargs
if isinstance(raw_kwargs, str):
try:
argument_dict = parse_partial_json(raw_kwargs) or {}
except Exception:
argument_dict = {}
else:
argument_dict = raw_kwargs or {}
tool_selections.append(
ToolSelection(View on GitHub (pinned to 4a030776a3)
Solutions
- Log response.message to see what the model said instead of calling the tool — often a clarification or refusal you can address in the prompt.
- Ensure tools are actually attached to the request and the schema is valid JSON Schema the model supports.
- Use a model with reliable function calling (per the Responses API docs) for tool-driven flows.
- If a text answer is acceptable in some cases, disable error_on_no_tool_call and handle the empty selection list.
Defensive patterns
Strategy: try-catch
Try / catch
try:
selections = extract_tool_selections(response, error_on_no_tool_call=True)
except ValueError as e:
if 'Expected tool calls' in str(e):
logger.warning('model declined tool call: %s', response.message.content)
selections = [] # fall back to plain-answer handling Prevention
- Verify tools are attached and schemas are valid before relying on mandatory tool calls.
- Prefer models with strong function-calling support; log refusals to detect prompt/schema problems early.
When it happens
Trigger: Using OpenAIResponses-based agents/structured output where the prompt or function-calling config expects a tool call, but the model returns a text response — weak function-calling models, missing tools in the request, schema the model rejects, or the model asking a clarifying question.
Common situations: Switching to a model with poor function-calling support; tool definitions omitted from the chat request; overly complex JSON schema the model refuses; temperature/max_tokens settings truncating the response before the tool call is emitted.
Related errors
- Configured model does not support function calling
- INVALID_REQUEST_ERROR
- OpenAI-like Responses LLM dependencies are not installed. In
- OpenAI Responses LLM dependencies are not installed. Install
- mistral-common only supports function tools.
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/3fae3a8381cbc739.
Report an issue: GitHub.