{"record":{"id":"90ed760fd282e28a","repo":"run-llama/llama_index","slug":"retriever-and-query-engine-ids-must-not-overlap","errorCode":null,"errorMessage":"Retriever and query engine ids must not overlap.","messagePattern":"Retriever and query engine ids must not overlap\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/retrievers/recursive_retriever.py","lineNumber":63,"sourceCode":"        query_engine_dict: Optional[Dict[str, BaseQueryEngine]] = None,\n        node_dict: Optional[Dict[str, BaseNode]] = None,\n        callback_manager: Optional[CallbackManager] = None,\n        query_response_tmpl: Optional[str] = None,\n        verbose: bool = False,\n    ) -> None:\n        \"\"\"Init params.\"\"\"\n        self._root_id = root_id\n        if root_id not in retriever_dict:\n            raise ValueError(\n                f\"Root id {root_id} not in retriever_dict, it must be a retriever.\"\n            )\n        self._retriever_dict = retriever_dict\n        self._query_engine_dict = query_engine_dict or {}\n        self._node_dict = node_dict or {}\n\n        # make sure keys don't overlap\n        if set(self._retriever_dict.keys()) & set(self._query_engine_dict.keys()):\n            raise ValueError(\"Retriever and query engine ids must not overlap.\")\n\n        self._query_response_tmpl = query_response_tmpl or DEFAULT_QUERY_RESPONSE_TMPL\n        super().__init__(callback_manager, verbose=verbose)\n\n    def _deduplicate_nodes(\n        self, nodes_with_score: List[NodeWithScore]\n    ) -> List[NodeWithScore]:\n        \"\"\"\n        Deduplicate nodes according to node id.\n        Keep the node with the highest score/first returned.\n        \"\"\"\n        node_ids = set()\n        deduplicate_nodes = []\n        for node_with_score in nodes_with_score:\n            node = node_with_score.node\n            if node.id_ not in node_ids:\n                node_ids.add(node.id_)\n                deduplicate_nodes.append(node_with_score)","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/retrievers/recursive_retriever.py#L45-L81","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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'."],"exampleFix":"# before\nretriever = RecursiveRetriever(\n    \"root\",\n    retriever_dict={\"data\": retriever},\n    query_engine_dict={\"data\": engine},\n)\n\n# after\nretriever = RecursiveRetriever(\n    \"root\",\n    retriever_dict={\"data\": retriever},\n    query_engine_dict={\"data_engine\": engine},\n)\n# and point the corresponding IndexNode at \"data_engine\"","handlingStrategy":"validation","validationCode":"overlap = set(retriever_dict) & set(query_engine_dict or {})\nassert not overlap, f\"id collision between dicts: {overlap}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assert the two dicts have disjoint keys before constructing the retriever.","Give retriever/engine pairs distinct suffixed ids and matching IndexNode references."],"tags":["retriever","recursive-retrieval","initialization","naming"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}