run-llama/llama_index · error · ValueError
Retriever and query engine ids must not overlap.
Error message
Retriever and query engine ids must not overlap.
What it means
RecursiveRetriever stores retriever_dict and query_engine_dict in one namespace: a QueryBundle id looked up during recursion is checked against retrievers first, then query engines, so an id present in both is ambiguous. __init__ therefore raises ValueError when the two dicts share any key (set intersection is non-empty).
Source
Thrown at llama-index-core/llama_index/core/retrievers/recursive_retriever.py:63
query_engine_dict: Optional[Dict[str, BaseQueryEngine]] = None,
node_dict: Optional[Dict[str, BaseNode]] = None,
callback_manager: Optional[CallbackManager] = None,
query_response_tmpl: Optional[str] = None,
verbose: bool = False,
) -> None:
"""Init params."""
self._root_id = root_id
if root_id not in retriever_dict:
raise ValueError(
f"Root id {root_id} not in retriever_dict, it must be a retriever."
)
self._retriever_dict = retriever_dict
self._query_engine_dict = query_engine_dict or {}
self._node_dict = node_dict or {}
# make sure keys don't overlap
if set(self._retriever_dict.keys()) & set(self._query_engine_dict.keys()):
raise ValueError("Retriever and query engine ids must not overlap.")
self._query_response_tmpl = query_response_tmpl or DEFAULT_QUERY_RESPONSE_TMPL
super().__init__(callback_manager, verbose=verbose)
def _deduplicate_nodes(
self, nodes_with_score: List[NodeWithScore]
) -> List[NodeWithScore]:
"""
Deduplicate nodes according to node id.
Keep the node with the highest score/first returned.
"""
node_ids = set()
deduplicate_nodes = []
for node_with_score in nodes_with_score:
node = node_with_score.node
if node.id_ not in node_ids:
node_ids.add(node.id_)
deduplicate_nodes.append(node_with_score)View on GitHub (pinned to afd0fef371)
Solutions
- Rename the colliding keys so every id is unique across both dicts, and update the corresponding IndexNode references (the node's index_id must match the new key).
- Generate ids from one source of truth and assert uniqueness before constructing the retriever.
- If you need both interfaces for one sub-index, suffix them: 'chunks_retriever' / 'chunks_engine'.
Example fix
# before
retriever = RecursiveRetriever(
"root",
retriever_dict={"data": retriever},
query_engine_dict={"data": engine},
)
# after
retriever = RecursiveRetriever(
"root",
retriever_dict={"data": retriever},
query_engine_dict={"data_engine": engine},
)
# and point the corresponding IndexNode at "data_engine" Defensive patterns
Strategy: validation
Validate before calling
overlap = set(retriever_dict) & set(query_engine_dict or {})
assert not overlap, f"id collision between dicts: {overlap}" Prevention
- Assert the two dicts have disjoint keys before constructing the retriever.
- Give retriever/engine pairs distinct suffixed ids and matching IndexNode references.
When it happens
Trigger: Building RecursiveRetriever with the same string (e.g. 'chunks') used both as a retriever id and a query engine id; generating ids for IndexNodes programmatically and accidentally registering the same id for a sub-index retriever and a sub-index query engine; copy-paste between the two dicts.
Common situations: Compositional pipelines where each sub-index is exposed both ways; loops creating {'id': index.as_retriever()} and {'id': index.as_query_engine()} with identical keys; tutorial code adapted with the same names for both.
Related errors
- Root id {root_id} not in retriever_dict, it must be a retrie
- Object {obj} is not retrievable.
- Query id {query_id} not found in either `retriever_dict` or
- Must be a retriever or query engine.
- LLM must be a FunctionCallingLLM
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/90ed760fd282e28a.
Report an issue: GitHub.