deepset-ai/haystack · error · ValueError
Tool execution requires at least one tool.
Error message
Tool execution requires at least one tool.
What it means
_validate_and_prepare_tools raises this ValueError when the tools list given to tool execution is empty. Running tools requires at least one callable tool to dispatch LLM tool calls against.
Source
Thrown at haystack/components/agents/tool_calling.py:54
_StateKeys = set[str] | _AllStateKeys
class ToolNotFoundException(Exception):
"""Exception raised when a tool is not found in the list of available tools."""
def __init__(self, tool_name: str, available_tools: list[str]) -> None:
message = f"Tool '{tool_name}' not found. Available tools: {', '.join(available_tools)}"
super().__init__(message)
def _validate_and_prepare_tools(tools: ToolsType) -> dict[str, Tool]:
"""
Flatten, deduplicate-check, and index tools by name.
:raises ValueError: If no tools are provided or if duplicate tool names are found.
"""
if not tools:
raise ValueError("Tool execution requires at least one tool.")
available_tools = flatten_tools_or_toolsets(tools)
_check_duplicate_tool_names(available_tools)
tool_names = [tool.name for tool in available_tools]
return dict(zip(tool_names, available_tools, strict=True))
def _merge_tool_outputs_into_state(tool: Tool, result: Any, state: State) -> None:
"""
Write tool outputs into State according to the tool's `outputs_to_state` mapping.
:raises RuntimeError: If writing an output value into the state fails.
"""
if not isinstance(result, dict):
return
for state_key, config in (tool.outputs_to_state or {}).items():View on GitHub (pinned to e318778c9b)
Solutions
- Pass at least one Tool or Toolset to the execution call
- Check upstream filtering logic that may have emptied the tools list
- If the Agent legitimately needs no tools, don't route tool_call messages to it
Example fix
// before run_tools(tools=[]) // after run_tools(tools=[my_tool])
Defensive patterns
Strategy: validation
Validate before calling
if not tools:
raise ValueError("Refusing to run tools: list is empty") Type guard
def has_tools(tools) -> bool:
return bool(tools) Try / catch
try:
result = run_tools(tools=tools, tool_call=call)
except ValueError as e:
if "at least one tool" in str(e):
result = fallback_answer_without_tools(call)
else:
raise Prevention
- Check len(tools) before invoking tool execution helpers
- Audit upstream filters that may empty the tools list
- Configure Agents with at least one tool if tool_call messages are expected
When it happens
Trigger: Calling _run_tool/_run_tool_async with tools=[] or None coercing to empty; an Agent configured with no tools receiving a tool_call message.
Common situations: Config where tools were filtered out upstream (all names rejected), or invoking low-level tool execution helpers directly with an empty list.
Related errors
- tools must be a list of Tool and/or Toolset objects, a Tools
- Tool '{tool.name}': failed to merge outputs into state. {e}
- No tools were configured for the Agent at initialization.
- Expected one ToolExecutionDecision for each tool call, but r
- No unused ToolExecutionDecision matches tool call {tc.tool_n
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/7033347a00ee9043.
Report an issue: GitHub.