{"record":{"id":"f4e610842fb4ed80","repo":"run-llama/llama_index","slug":"must-be-a-retriever-or-query-engine","errorCode":null,"errorMessage":"Must be a retriever or query engine.","messagePattern":"Must be a retriever or query engine\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/retrievers/recursive_retriever.py","lineNumber":204,"sourceCode":"                query_bundle, nodes\n            )\n\n        elif isinstance(obj, BaseQueryEngine):\n            sub_resp = obj.query(query_bundle)\n            if self._verbose:\n                print_text(\n                    f\"Got response: {sub_resp!s}\\n\",\n                    color=\"green\",\n                )\n            # format with both the query and the response\n            node_text = self._query_response_tmpl.format(\n                query_str=query_bundle.query_str, response=str(sub_resp)\n            )\n            node = TextNode(text=node_text)\n            nodes_to_add = [NodeWithScore(node=node, score=cur_similarity)]\n            additional_nodes = sub_resp.source_nodes\n        else:\n            raise ValueError(\"Must be a retriever or query engine.\")\n\n        return nodes_to_add, additional_nodes\n\n    def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:\n        retrieved_nodes, _ = self._retrieve_rec(query_bundle, query_id=None)\n        return retrieved_nodes\n\n    def retrieve_all(\n        self, query_bundle: QueryBundle\n    ) -> Tuple[List[NodeWithScore], List[NodeWithScore]]:\n        \"\"\"\n        Retrieve all nodes.\n\n        Unlike default `retrieve` method, this also fetches additional sources.\n\n        \"\"\"\n        return self._retrieve_rec(query_bundle, query_id=None)\n","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/retrievers/recursive_retriever.py#L186-L222","documentation":"In _retrieve_rec, the object resolved for a query_id must be a BaseRetriever or a BaseQueryEngine to drive the next recursion step; _get_object can also return a BaseNode from node_dict, which is handled in an earlier isinstance branch. This ValueError fires when the resolved object is none of those types, typically because something of the wrong type was stored in one of the dicts.","triggerScenarios":"Putting a query engine tool, agent, index, or other object into retriever_dict/query_engine_dict instead of an actual retriever/query engine; storing a non-node object in node_dict; passing wrapped objects (e.g. RetrieverQueryEngine around the wrong layer, or a FunctionTool) where the raw engine is expected.","commonSituations":"Compositional pipelines evolved over time where a dict slot silently changed type; wrapping sub-indexes in tools for agents and reusing the same dict for RecursiveRetriever; type-erased config-driven construction (dict[str, Any]) letting wrong objects through.","solutions":["Store only BaseRetriever instances in retriever_dict and BaseQueryEngine instances in query_engine_dict (e.g. index.as_retriever() / index.as_query_engine(), not the index itself).","Unwrap tools/agents down to the underlying retriever or query engine before registering them.","Type-check the dicts at construction time and fail fast with the offending key and type."],"exampleFix":"# before\nretriever_dict = {\n    \"root\": vector_index.as_query_engine(),  # query engine in retriever slot\n}\n\n# after\nretriever_dict = {\"root\": vector_index.as_retriever()}\nquery_engine_dict = {\"root_qe\": vector_index.as_query_engine()}","handlingStrategy":"type-guard","validationCode":"from llama_index.core import BaseRetriever\nfrom llama_index.core.query_engine import BaseQueryEngine\nfor k, v in {**retriever_dict, **query_engine_dict}.items():\n    assert isinstance(v, (BaseRetriever, BaseQueryEngine)), f\"{k} has invalid type {type(v)}\"","typeGuard":"from llama_index.core import BaseRetriever\nfrom llama_index.core.query_engine import BaseQueryEngine\n\ndef is_valid_recursion_target(obj) -> bool:\n    return isinstance(obj, (BaseRetriever, BaseQueryEngine))","tryCatchPattern":null,"preventionTips":["Only register as_retriever()/as_query_engine() results in the dicts.","Unwrap tools/agents to the underlying retriever or engine before registration.","Type-check dict contents once at construction with clear key/type diagnostics."],"tags":["retriever","recursive-retrieval","type-error","type-guard"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}