alibaba/spring-ai-alibaba · error · IllegalStateException

Failed to get valid decision after %d retries. Last invalid

Error message

Failed to get valid decision after %d retries. Last invalid decision: %s

What it means

RoutingEdgeAction.getDecisionWithRetry() exhausts all retry attempts without obtaining a structurally valid routing decision from the LLM and throws an IllegalStateException naming the retry count and last invalid decision. The router expected a parseable decision (e.g. structured routing output naming a sub-agent) and the model kept returning invalid or unparseable responses.

Source

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

				else {
					// Invalid agent name, store for next retry
					lastInvalidDecision = decisionValue;
					logger.warn("RoutingAgent {} attempt {}/{} returned invalid agent name: {}",
							rootAgent.name(), attempt, maxRetries, decisionValue);
				}
			}
			catch (Exception e) {
				if (attempt == maxRetries) {
					// Last attempt failed, rethrow the exception
					logger.error("RoutingAgent {} failed on final attempt {}/{}", rootAgent.name(), attempt, maxRetries, e);
					throw e;
				}
				logger.warn("RoutingAgent {} attempt {}/{} encountered an error, will retry", rootAgent.name(), attempt, maxRetries, e);
			}
		}

		// All retries exhausted
		throw new IllegalStateException(
				String.format("Failed to get valid decision after %d retries. Last invalid decision: %s",
						maxRetries, lastInvalidDecision));
	}

	/**
	 * Response record for structured routing decision output
	 */
	public record RoutingDecision(String agent) { }
}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Use a model that reliably follows the structured routing format (or enable structured output) for the router
  2. Check the lastInvalidDecision in the message and fix the routing prompt/schema so its output parses
  3. Verify the agent names the router can return match the registered sub-agents
  4. Increase maxRetries or configure a fallback decision if supported

Example fix

// before
RoutingAgent.builder().model(weakModel).subAgents(a, b).build();
// after
RoutingAgent.builder().model(structuredOutputModel)
    .subAgents(a, b)
    .fallbackAgent(defaultAgent) // or validate prompt format
    .build();
Defensive patterns

Strategy: retry

Validate before calling

// pre-validate: ensure router model supports structured output and sub-agent names are registered
Set<String> valid = subAgents.stream().map(Agent::name).collect(java.util.stream.Collectors.toSet());

Type guard

boolean isParsableDecision(String raw, Set<String> validAgents) { return raw != null && validAgents.contains(raw.trim()); }

Try / catch

try { decision = routingEdgeAction.decisionValue(state); } catch (IllegalStateException e) { if (e.getMessage().contains("Failed to get valid decision")) { /* use default route or abort gracefully */ } else throw e; }

Prevention

When it happens

Trigger: The routing LLM repeatedly returns responses that fail decision parsing/validation for maxRetries attempts while RoutingAgent evaluates its edge action.

Common situations: Model output doesn't match the expected routing format (missing JSON, wrong agent names); weak/small model used for routing; prompt drift after changing sub-agent names; transient model errors consuming all retries.

Related errors


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