alibaba/spring-ai-alibaba · error · IllegalStateException

RoutingAgent failed to get valid decision after retries. In

Error message

RoutingAgent  failed to get valid decision after retries. Invalid agents: [].

What it means

RoutingNode.apply() throws IllegalStateException when, after DEFAULT_MAX_RETRIES, the routing decisions still name only invalid (unregistered) agents and no fallback is configured. The message lists the agent names the router returned that do not exist on the RoutingAgent.

Source

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

		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));
			}
			
			// Return MultiCommand with the routing decisions as gotoNodes and agent queries in state.
			// Each agent's query is stored as independent key: agentName_input
			Map<String, Object> stateUpdate = new HashMap<>();
			decision.getAgentQueries().forEach((agentName, query) ->
					stateUpdate.put(agentName + "_input", query));
			return new MultiCommand(decisionValues, stateUpdate);
		}
		else {
			logger.error("RoutingAgent {} failed to get valid decision after {} retries. Invalid agents: {}.",
					rootAgent.name(), DEFAULT_MAX_RETRIES, invalidAgents);
			throw new IllegalStateException(
					"RoutingAgent " + rootAgent.name() + " failed to get valid decision after retries. Invalid agents: " + invalidAgents + ".");
		}
	}

	private MultiCommand createFallbackCommand(OverAllState state, List<Message> messages) {
		if (!(rootAgent instanceof LlmRoutingAgent llmRoutingAgent)) {
			return null;
		}

		String fallbackAgent = llmRoutingAgent.getFallbackAgent();
		if (!StringUtils.hasText(fallbackAgent)
				|| subAgents.stream().noneMatch(agent -> agent.name().equals(fallbackAgent))) {
			return null;
		}

		String fallbackInput = state.value("input").map(Object::toString).orElseGet(() -> {
			for (int i = messages.size() - 1; i >= 0; i--) {
				if (messages.get(i) instanceof UserMessage userMessage) {

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Make the LLM's candidate agent names exactly match the registered sub-agent names (check the listed invalid agents against rootAgent's subAgents)
  2. Configure a fallback on the RoutingAgent so invalid decisions degrade gracefully instead of throwing
  3. Update the routing prompt/descriptions after any sub-agent rename; strengthen instructions to only pick from the given list

Example fix

// before
// router returns "data_fetch" but agent registered "dataFetch"
RoutingAgent.builder().name("router").model(model).subAgents(dataFetch, summarize).build();
// after
RoutingAgent.builder().name("router").model(model).subAgents(dataFetch, summarize)
    .fallback(dataFetch) // ensure names in prompt match exactly
    .build();
Defensive patterns

Strategy: fallback

Validate before calling

List<String> registered = rootAgent.subAgents().stream().map(a -> a.name()).toList();
// ensure routing prompt lists exactly these names

Type guard

boolean isValidAgentName(String n, java.util.List<Agent> agents) { return agents.stream().anyMatch(a -> a.name().equals(n)); }

Try / catch

try { cmd = routingNode.apply(state); } catch (IllegalStateException e) { if (e.getMessage().contains("failed to get valid decision")) { /* route to fallback agent */ } else throw e; }

Prevention

When it happens

Trigger: The routing LLM returns sub-agent names that don't match any registered sub-agent (typo, renamed agent, hallucinated name) on every retry, and no fallback is set.

Common situations: Renaming or removing a sub-agent without updating the routing prompt/description; the model invents plausible but unregistered agent names; case/format mismatches between LLM output and registered names.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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