run-llama/llama_index · error · ValueError
Must be a retriever or query engine.
Error message
Must be a retriever or query engine.
What it means
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.
Source
Thrown at llama-index-core/llama_index/core/retrievers/recursive_retriever.py:204
query_bundle, nodes
)
elif isinstance(obj, BaseQueryEngine):
sub_resp = obj.query(query_bundle)
if self._verbose:
print_text(
f"Got response: {sub_resp!s}\n",
color="green",
)
# format with both the query and the response
node_text = self._query_response_tmpl.format(
query_str=query_bundle.query_str, response=str(sub_resp)
)
node = TextNode(text=node_text)
nodes_to_add = [NodeWithScore(node=node, score=cur_similarity)]
additional_nodes = sub_resp.source_nodes
else:
raise ValueError("Must be a retriever or query engine.")
return nodes_to_add, additional_nodes
def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
retrieved_nodes, _ = self._retrieve_rec(query_bundle, query_id=None)
return retrieved_nodes
def retrieve_all(
self, query_bundle: QueryBundle
) -> Tuple[List[NodeWithScore], List[NodeWithScore]]:
"""
Retrieve all nodes.
Unlike default `retrieve` method, this also fetches additional sources.
"""
return self._retrieve_rec(query_bundle, query_id=None)
View on GitHub (pinned to afd0fef371)
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.
Example fix
# before
retriever_dict = {
"root": vector_index.as_query_engine(), # query engine in retriever slot
}
# after
retriever_dict = {"root": vector_index.as_retriever()}
query_engine_dict = {"root_qe": vector_index.as_query_engine()} Defensive patterns
Strategy: type-guard
Validate before calling
from llama_index.core import BaseRetriever
from llama_index.core.query_engine import BaseQueryEngine
for k, v in {**retriever_dict, **query_engine_dict}.items():
assert isinstance(v, (BaseRetriever, BaseQueryEngine)), f"{k} has invalid type {type(v)}" Type guard
from llama_index.core import BaseRetriever
from llama_index.core.query_engine import BaseQueryEngine
def is_valid_recursion_target(obj) -> bool:
return isinstance(obj, (BaseRetriever, BaseQueryEngine)) Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Object {obj} is not retrievable.
- Root id {root_id} not in retriever_dict, it must be a retrie
- Retriever and query engine ids must not overlap.
- Query id {query_id} not found in either `retriever_dict` or
- LLM must be a FunctionCallingLLM
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/f4e610842fb4ed80.
Report an issue: GitHub.