run-llama/llama_index · error · ValueError
Unknown tool name: {tool_call_result.tool_name}
Error message
Unknown tool name: {tool_call_result.tool_name} What it means
QueryPlanTool.__call__ parses the LLM's JSON kwargs into a QueryPlan (a DAG of QueryNode dependencies) and requires exactly one root node — a node that no other node references as a dependency. If _find_root_nodes returns more than one root, the plan is ambiguous (multiple independent answer chains) and execution refuses to proceed.
Source
Thrown at llama-index-core/llama_index/core/agent/workflow/codeact_agent.py:380
# Format the output as a tool response message
if tool_call_result.tool_name == EXECUTE_TOOL_NAME:
code_result = f"Result of executing the code given:\n\n{tool_call_result.tool_output.content}"
scratchpad.append(
ChatMessage(
role="user",
content=code_result,
)
)
elif tool_call_result.tool_name == "handoff":
scratchpad.append(
ChatMessage(
role="tool",
blocks=tool_call_result.tool_output.blocks,
additional_kwargs={"tool_call_id": tool_call_result.tool_id},
)
)
else:
raise ValueError(f"Unknown tool name: {tool_call_result.tool_name}")
await ctx.store.set(self.scratchpad_key, scratchpad)
async def finalize(
self, ctx: Context, output: AgentOutput, memory: BaseMemory
) -> AgentOutput:
"""
Finalize the code act agent.
Adds all in-progress messages to memory.
"""
scratchpad: List[ChatMessage] = await ctx.store.get(
self.scratchpad_key, default=[]
)
await memory.aput_messages(scratchpad)
# reset scratchpad
await ctx.store.set(self.scratchpad_key, [])View on GitHub (pinned to afd0fef371)
Solutions
- Retry the tool call so the LLM regenerates a single-root plan (add a corrective system-prompt instruction: 'exactly one root node').
- Fix hand-built plans: ensure every node except one is referenced in some other node's sources.
- Validate plan structure before calling: compute root nodes yourself and reject/repair multi-root plans.
- Use a stronger model or simplified sub-question decomposition for multi-hop queries.
Example fix
# before
plan = {"nodes": [
{"id": 1, "query_str": "A?", "sources": []},
{"id": 2, "query_str": "B?", "sources": []}, # second root -> ValueError
]}
tool(**plan)
# after
plan = {"nodes": [
{"id": 1, "query_str": "A?", "sources": []},
{"id": 2, "query_str": "B?", "sources": []},
{"id": 3, "query_str": "Combine A and B", "sources": [1, 2]}, # single root
]}
tool(**plan) Defensive patterns
Strategy: validation
Validate before calling
def root_ids(nodes):
used = {s for n in nodes for s in n.sources}
return [n.id for n in nodes if n.id not in used]
plan = QueryPlan(**kwargs)
roots = root_ids(plan.nodes)
if len(roots) != 1:
# repair: attach orphan nodes to a synthesis root, or reject and re-plan
... Type guard
def plan_has_single_root(nodes) -> bool:
used = {src for n in nodes for src in n.sources}
return sum(1 for n in nodes if n.id not in used) == 1 Try / catch
try:
out = tool(**plan_kwargs)
except ValueError as e:
if 'exactly one root node' in str(e):
# ask the LLM to regenerate a single-root plan
plan_kwargs = regenerate_plan(prompt)
out = tool(**plan_kwargs) Prevention
- Instruct the model explicitly to produce exactly one root (final synthesis) node.
- Validate plan DAG before executing: single root, no orphans.
- Use few-shot examples showing correct single-root multi-hop plans.
When it happens
Trigger: The LLM emitting a plan JSON with two or more nodes that are never used as sources by other nodes; hand-crafted QueryPlan objects with disconnected subgraphs; hallucinated node ids in 'source' fields that accidentally orphan intended child nodes, leaving multiple roots.
Common situations: Using QueryPlanTool with weaker models that produce malformed dependency graphs; prompt changes that confuse the plan schema; complex multi-hop questions where the model forks the plan; few-shot examples demonstrating multi-root plans.
Related errors
- Max iterations of {max_iterations} reached! Either something
- No tool calls found, cannot aggregate results.
- Tool {tool.metadata.name} requires context. CodeActAgent onl
- Tool {tool.metadata.name} is not a FunctionTool. CodeActAgen
- llm must be a function calling LLM to use handoff
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/8cd8a80b2fe4f3ef.
Report an issue: GitHub.