run-llama/llama_index · error · ValueError

Failed to select retriever

Error message

Failed to select retriever

What it means

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.

Source

Thrown at llama-index-core/llama_index/core/retrievers/router_retriever.py:99

            payload={EventPayload.QUERY_STR: query_bundle.query_str},
        ) as query_event:
            result = self._selector.select(self._metadatas, query_bundle)

            if len(result.inds) > 1:
                retrieved_results = {}
                for i, engine_ind in enumerate(result.inds):
                    logger.info(
                        f"Selecting retriever {engine_ind}: {result.reasons[i]}."
                    )
                    selected_retriever = self._retrievers[engine_ind]
                    cur_results = selected_retriever.retrieve(query_bundle)
                    retrieved_results.update({n.node.node_id: n for n in cur_results})
            else:
                try:
                    selected_retriever = self._retrievers[result.ind]
                    logger.info(f"Selecting retriever {result.ind}: {result.reason}.")
                except ValueError as e:
                    raise ValueError("Failed to select retriever") from e

                cur_results = selected_retriever.retrieve(query_bundle)
                retrieved_results = {n.node.node_id: n for n in cur_results}

            query_event.on_end(payload={EventPayload.NODES: retrieved_results.values()})

        return list(retrieved_results.values())

    async def _aretrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
        with self.callback_manager.event(
            CBEventType.RETRIEVE,
            payload={EventPayload.QUERY_STR: query_bundle.query_str},
        ) as query_event:
            result = await self._selector.aselect(self._metadatas, query_bundle)

            if len(result.inds) > 1:
                retrieved_results = {}
                tasks = []

View on GitHub (pinned to afd0fef371)

Solutions

  1. Switch to a Pydantic/structured selector (RouterRetriever.from_defaults with an LLMPydanticSingleSelector) so the LLM cannot emit an out-of-range index
  2. Verify len(retriever_tools) matches the numbered choices the selector sees, and that your custom BaseSelector returns 0-based indexes within range
  3. Use a stronger LLM for selection (the default prompt asks the model to pick by number; small models frequently miscount)
  4. Reduce the number of choices, or set select_multi=False so only one index must be parsed

Example fix

# before
router = RouterRetriever.from_defaults(retriever_tools=tools, select_multi=False)

# after
from llama_index.core.selectors import LLMSingleSelector
from llama_index.core.selectors.pydantic_selectors import PydanticSingleSelector
router = RouterRetriever.from_defaults(
    retriever_tools=tools,
    selector=PydanticSingleSelector.from_defaults(),  # structured output, index always in range
)
Defensive patterns

Strategy: try-catch

Validate before calling

n = len(retriever_tools)
assert all(0 <= i < n for i in range(n)), "tool count sanity"  # and for custom selectors:
# assert 0 <= selector_result.ind < len(retriever_tools)

Type guard

def valid_selection(ind: int, n_tools: int) -> bool:
    return isinstance(ind, int) and 0 <= ind < n_tools

Try / catch

try:
    nodes = router_retriever.retrieve(query)
except ValueError as e:
    if "Failed to select retriever" in str(e):
        nodes = fallback_retriever.retrieve(query)  # log selector failure first
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/a17cd74e39e4769d. Report an issue: GitHub.