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
- Make the LLM's candidate agent names exactly match the registered sub-agent names (check the listed invalid agents against rootAgent's subAgents)
- Configure a fallback on the RoutingAgent so invalid decisions degrade gracefully instead of throwing
- 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
- Always configure a fallback on RoutingAgents
- Keep sub-agent names in sync with the routing prompt
- After renaming a sub-agent, grep routing prompts/configs for the old name
- Restrict LLM output to enumerated agent names via structured output
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
- Failed to get valid decision after %d retries. Last invalid
- Failed to get valid decision after %d retries. Last invalid
- Invalid data format
- INVALID_PARAMS
- WORKFLOW_CONFIG_INVALID
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/210c444365788928.
Report an issue: GitHub.