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.
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
- Expected one ToolExecutionDecision for each tool call, but…
- No tools were configured for the Agent at initialization.
- No unused ToolExecutionDecision matches tool call
- Tool ' ': failed to merge outputs into state.
- tools must be a list of Tool and/or Toolset objects, a…
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/7033347a00ee9043.
Report an issue: GitHub.
Appendix: 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)