run-llama/llama_index · error · ValueError
No tool calls found, cannot aggregate results.
Error message
No tool calls found, cannot aggregate results.
What it means
FunctionTool.__init__ raises when metadata is None after fn/async_fn handling: a FunctionTool must carry ToolMetadata (name, description) because agents and LLMs rely on it for tool selection. Unlike from_defaults, plain construction does not infer metadata from the function signature, so omitting it is fatal.
Source
Thrown at llama-index-core/llama_index/core/agent/workflow/base_agent.py:668
result_ev = ToolCallResult(
tool_name=ev.tool_name,
tool_kwargs=ev.tool_kwargs,
tool_id=ev.tool_id,
tool_output=result,
return_direct=tool.metadata.return_direct if tool else False,
)
ctx.write_event_to_stream(result_ev)
return result_ev
@step
async def aggregate_tool_results(
self, ctx: Context, ev: ToolCallResult
) -> Union[AgentInput, StopEvent, None]:
"""Aggregate tool results and return the next agent input."""
num_tool_calls = await ctx.store.get("num_tool_calls", default=0)
if num_tool_calls == 0:
raise ValueError("No tool calls found, cannot aggregate results.")
tool_call_results: list[ToolCallResult] = ctx.collect_events( # type: ignore
ev, expected=[ToolCallResult] * num_tool_calls
)
if not tool_call_results:
return None
memory: BaseMemory = await ctx.store.get("memory")
# track tool calls made during a .run() call
cur_tool_calls: List[ToolCallResult] = await ctx.store.get(
"current_tool_calls", default=[]
)
cur_tool_calls.extend(tool_call_results)
await ctx.store.set("current_tool_calls", cur_tool_calls)
await self.handle_tool_call_results(ctx, tool_call_results, memory)
View on GitHub (pinned to afd0fef371)
Solutions
- Supply ToolMetadata: FunctionTool(fn=f, metadata=ToolMetadata(name='f', description='does f')).
- Or use FunctionTool.from_defaults(fn=f, name='f', description='...') which builds metadata for you.
- In bulk-construction loops, validate each metadata entry is not None before constructing.
Example fix
# before
tool = FunctionTool(fn=search_web) # ValueError: metadata must be provided
# after
from llama_index.core.tools import FunctionTool, ToolMetadata
tool = FunctionTool(
fn=search_web,
metadata=ToolMetadata(name="search_web", description="Search the web"),
) Defensive patterns
Strategy: validation
Validate before calling
from llama_index.core.tools import ToolMetadata
if metadata is None:
metadata = ToolMetadata(name=fn.__name__, description=fn.__doc__ or fn.__name__)
tool = FunctionTool(fn=fn, metadata=metadata) Type guard
from llama_index.core.tools.tool_metadata import ToolMetadata
def valid_metadata(md) -> bool:
return isinstance(md, ToolMetadata) Prevention
- Prefer FunctionTool.from_defaults(fn=..., name=..., description=...).
- Always pair fn with an explicit ToolMetadata in direct construction.
- In bulk creation, fail fast if a metadata lookup returns None.
When it happens
Trigger: FunctionTool(fn=my_func) with no metadata argument; passing metadata=None explicitly; code ported from FunctionTool.from_defaults(fn=...) (which auto-derives metadata) to direct construction without adding metadata.
Common situations: Copy-paste from examples that use from_defaults while switching to the class constructor; refactors that drop the metadata kwarg; building many tools in a loop where one iteration's metadata dict lookup returns None.
Related errors
- Max iterations of {max_iterations} reached! Either something
- Tool {tool.metadata.name} requires context. CodeActAgent onl
- Tool {tool.metadata.name} is not a FunctionTool. CodeActAgen
- code_execute_fn must be provided for CodeActAgent
- LLM must be a FunctionCallingLLM
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/f69cb4c6307d8e99.
Report an issue: GitHub.