{"record":{"id":"a17cd74e39e4769d","repo":"run-llama/llama_index","slug":"failed-to-select-retriever","errorCode":null,"errorMessage":"Failed to select retriever","messagePattern":"Failed to select retriever","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/retrievers/router_retriever.py","lineNumber":99,"sourceCode":"            payload={EventPayload.QUERY_STR: query_bundle.query_str},\n        ) as query_event:\n            result = self._selector.select(self._metadatas, query_bundle)\n\n            if len(result.inds) > 1:\n                retrieved_results = {}\n                for i, engine_ind in enumerate(result.inds):\n                    logger.info(\n                        f\"Selecting retriever {engine_ind}: {result.reasons[i]}.\"\n                    )\n                    selected_retriever = self._retrievers[engine_ind]\n                    cur_results = selected_retriever.retrieve(query_bundle)\n                    retrieved_results.update({n.node.node_id: n for n in cur_results})\n            else:\n                try:\n                    selected_retriever = self._retrievers[result.ind]\n                    logger.info(f\"Selecting retriever {result.ind}: {result.reason}.\")\n                except ValueError as e:\n                    raise ValueError(\"Failed to select retriever\") from e\n\n                cur_results = selected_retriever.retrieve(query_bundle)\n                retrieved_results = {n.node.node_id: n for n in cur_results}\n\n            query_event.on_end(payload={EventPayload.NODES: retrieved_results.values()})\n\n        return list(retrieved_results.values())\n\n    async def _aretrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:\n        with self.callback_manager.event(\n            CBEventType.RETRIEVE,\n            payload={EventPayload.QUERY_STR: query_bundle.query_str},\n        ) as query_event:\n            result = await self._selector.aselect(self._metadatas, query_bundle)\n\n            if len(result.inds) > 1:\n                retrieved_results = {}\n                tasks = []","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/retrievers/router_retriever.py#L81-L117","documentation":"RouterRetriever._retrieve asks a selector to pick one of its candidate retrievers and then indexes self._retrievers with result.ind. If the selector returns an index that cannot resolve to a retriever, the failed lookup is re-raised as ValueError('Failed to select retriever'). In practice the selector (often an LLM-backed one) produced an index that does not map to the registered retriever_tools list.","triggerScenarios":"Calling retrieve() on a RouterRetriever (or RouterQueryEngine) where the selector's chosen result.ind fails to index into the retriever list — e.g. an LLMSingleSelector parses the model's answer into an index that is out of range for the number of RetrieverTools supplied.","commonSituations":"Using LLMSingleSelector/LLMMultiSelector with a weak LLM that emits a wrong number in the selection output; adding/removing retriever_tools so indexes no longer match the prompt's numbered choices; custom selectors returning 1-based indexes.","solutions":["Switch to a Pydantic/structured selector (RouterRetriever.from_defaults with an LLMPydanticSingleSelector) so the LLM cannot emit an out-of-range index","Verify len(retriever_tools) matches the numbered choices the selector sees, and that your custom BaseSelector returns 0-based indexes within range","Use a stronger LLM for selection (the default prompt asks the model to pick by number; small models frequently miscount)","Reduce the number of choices, or set select_multi=False so only one index must be parsed"],"exampleFix":"# before\nrouter = RouterRetriever.from_defaults(retriever_tools=tools, select_multi=False)\n\n# after\nfrom llama_index.core.selectors import LLMSingleSelector\nfrom llama_index.core.selectors.pydantic_selectors import PydanticSingleSelector\nrouter = RouterRetriever.from_defaults(\n    retriever_tools=tools,\n    selector=PydanticSingleSelector.from_defaults(),  # structured output, index always in range\n)","handlingStrategy":"try-catch","validationCode":"n = len(retriever_tools)\nassert all(0 <= i < n for i in range(n)), \"tool count sanity\"  # and for custom selectors:\n# assert 0 <= selector_result.ind < len(retriever_tools)","typeGuard":"def valid_selection(ind: int, n_tools: int) -> bool:\n    return isinstance(ind, int) and 0 <= ind < n_tools","tryCatchPattern":"try:\n    nodes = router_retriever.retrieve(query)\nexcept ValueError as e:\n    if \"Failed to select retriever\" in str(e):\n        nodes = fallback_retriever.retrieve(query)  # log selector failure first\n    else:\n        raise","preventionTips":["Prefer pydantic/structured selectors over free-text LLM selectors","Keep retriever_tools count small and stable","Test custom selectors return 0-based in-range indexes"],"tags":["retriever","router","selector","llm-parsing"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}