alibaba/spring-ai-alibaba · error

RoutingAgent exhausted routing retries. Routing to fallback…

Error message

RoutingAgent {} exhausted routing retries. Routing to fallback agent {}.

What it means

RoutingNode.apply, after getDecisionWithRetry exhausts DEFAULT_MAX_RETRIES without a valid RoutingDecision: if a fallback agent is configured it logs this warning and routes there; the message marks degradation from LLM-based routing to the fallback path.

Solutions

  1. Configure a fallback agent so exhausted retries degrade gracefully
  2. Improve the routing system prompt and available-agent descriptions
  3. Increase DEFAULT_MAX_RETRIES or loosen decision validation
  4. Check the ChatModel for malformed/empty structured outputs
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/flow/node/RoutingNode.java:113 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/3c0963b46d6d4a37. Report an issue: GitHub.

Appendix: source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/flow/node/RoutingNode.java:113

		this.chatClient = ChatClient.builder(chatModel).defaultSystem(sb.toString()).build();
	}

	@Override
	public MultiCommand apply(OverAllState state, RunnableConfig config) throws Exception {
		@SuppressWarnings("unchecked")
		List<Message> messages = (List<Message>) state.value("messages").orElse(List.of());
		
		// Prepare messages with instruction if available
		List<Message> messagesWithInstruction = prepareMessagesWithInstruction(messages);
		
		RoutingDecision decision;
		try {
			decision = getDecisionWithRetry(messagesWithInstruction, DEFAULT_MAX_RETRIES);
		}
		catch (Exception e) {
			MultiCommand fallbackCommand = createFallbackCommand(state, messages);
			if (fallbackCommand != null) {
				logger.warn("RoutingAgent {} exhausted routing retries. Routing to fallback agent {}.",
						rootAgent.name(), fallbackCommand.gotoNodes().get(0));
				return fallbackCommand;
			}
			throw e;
		}
		List<String> decisionValues = decision.getAgentNames();

		// Validate all agent names are valid
		List<String> invalidAgents = decisionValues.stream()
				.filter(agentName -> subAgents.stream().noneMatch(agent -> agent.name().equals(agentName)))
				.collect(Collectors.toList());
				
		if (invalidAgents.isEmpty() && !decisionValues.isEmpty()) {
			if (decisionValues.size() == 1) {
				logger.info("RoutingAgent {} routed to single sub-agent {}.", rootAgent.name(), decisionValues.get(0));
			} else {
				logger.info("RoutingAgent {} routed to {} sub-agents in parallel: {}.", 
						rootAgent.name(), decisionValues.size(), String.join(", ", decisionValues));

View on GitHub (pinned to f82da0b50f)