run-llama/llama_index · error · ValueError
Node must have a tool_name in metadata.
Error message
Node must have a tool_name in metadata.
What it means
default_node_to_metadata_fn converts a retrieved Node into ToolMetadata for the deprecated RetrieverRouterQueryEngine. It requires the node metadata dict to contain a 'tool_name' key, which becomes the tool name; the node text becomes the description. Missing key raises ValueError.
Source
Thrown at llama-index-core/llama_index/core/query_engine/router_query_engine.py:260
# add selected result
final_response.metadata = final_response.metadata or {}
final_response.metadata["selector_result"] = result
query_event.on_end(payload={EventPayload.RESPONSE: final_response})
return final_response
def default_node_to_metadata_fn(node: BaseNode) -> ToolMetadata:
"""
Default node to metadata function.
We use the node's text as the Tool description.
"""
metadata = node.metadata or {}
if "tool_name" not in metadata:
raise ValueError("Node must have a tool_name in metadata.")
return ToolMetadata(name=metadata["tool_name"], description=node.get_content())
class RetrieverRouterQueryEngine(BaseQueryEngine):
"""
Retriever-based router query engine.
NOTE: this is deprecated, please use our new ToolRetrieverRouterQueryEngine
Use a retriever to select a set of Nodes. Each node will be converted
into a ToolMetadata object, and also used to retrieve a query engine, to form
a QueryEngineTool.
NOTE: this is a beta feature. We are figuring out the right interface
between the retriever and query engine.
Args:
selector (BaseSelector): A selector that chooses one out of many options basedView on GitHub (pinned to afd0fef371)
Solutions
- Add metadata={"tool_name": "..."} to each node/document before indexing so default_node_to_metadata_fn can map it
- Pass a custom node_to_metadata_fn to RetrieverRouterQueryEngine that derives a tool name without requiring 'tool_name'
- Migrate to ToolRetrieverRouterQueryEngine, which routes over QueryEngineTool objects and does not need node metadata
Example fix
// before
doc = Document(text="Handles billing questions")
index = SummaryIndex.from_documents([doc])
router = RetrieverRouterQueryEngine(retriever=index.as_retriever(), node_to_query_engine_fn=fn)
// after
doc = Document(
text="Handles billing questions",
metadata={"tool_name": "billing_engine"},
)
index = SummaryIndex.from_documents([doc])
router = RetrieverRouterQueryEngine(retriever=index.as_retriever(), node_to_query_engine_fn=fn) Defensive patterns
Strategy: validation
Validate before calling
def node_has_tool_name(node) -> bool:
return bool((node.metadata or {}).get("tool_name"))
assert all(node_has_tool_name(n) for n in routing_index.docstore.docs.values()), \
"every routing node needs metadata['tool_name']" Type guard
from llama_index.core.schema import BaseNode
def is_routable_node(node: BaseNode) -> bool:
"""Node can be converted by default_node_to_metadata_fn."""
return "tool_name" in (node.metadata or {}) Prevention
- Inject metadata={'tool_name': ...} at Document creation for routing indexes
- Prefer the non-deprecated ToolRetrieverRouterQueryEngine over RetrieverRouterQueryEngine
- Supply a custom node_to_metadata_fn when nodes cannot carry tool_name
When it happens
Trigger: Building RetrieverRouterQueryEngine over an index whose nodes lack metadata['tool_name'] while using the default node_to_query_engine_fn/metadata conversion (i.e. not supplying a custom node_to_metadata_fn or custom node_to_query_engine_fn).
Common situations: Indexing documents without per-node metadata, or migrating from an old workflow where tool_name was injected into node metadata. The class itself is deprecated in favor of ToolRetrieverRouterQueryEngine.
Related errors
- Retrieved more than one node.
- No tool calls found, cannot aggregate results.
- There are {len(self.reasons)} selections, please use .reason
- ref_doc_id of node cannot be None when building a document s
- ref_doc_id of node cannot be None when building a document s
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/5a6ff421b04aef2a.
Report an issue: GitHub.