{"record":{"id":"8a65799305baad85","repo":"alibaba/spring-ai-alibaba","slug":"failed-to-get-valid-decision-after-d-retries-las","errorCode":null,"errorMessage":"Failed to get valid decision after %d retries. Last invalid decision: %s","messagePattern":"Failed to get valid decision after (.+?) retries\\. Last invalid decision: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/flow/node/RoutingEdgeAction.java","lineNumber":236,"sourceCode":"\t\t\t\telse {\n\t\t\t\t\t// Invalid agent name, store for next retry\n\t\t\t\t\tlastInvalidDecision = decisionValue;\n\t\t\t\t\tlogger.warn(\"RoutingAgent {} attempt {}/{} returned invalid agent name: {}\",\n\t\t\t\t\t\t\trootAgent.name(), attempt, maxRetries, decisionValue);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception e) {\n\t\t\t\tif (attempt == maxRetries) {\n\t\t\t\t\t// Last attempt failed, rethrow the exception\n\t\t\t\t\tlogger.error(\"RoutingAgent {} failed on final attempt {}/{}\", rootAgent.name(), attempt, maxRetries, e);\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t\tlogger.warn(\"RoutingAgent {} attempt {}/{} encountered an error, will retry\", rootAgent.name(), attempt, maxRetries, e);\n\t\t\t}\n\t\t}\n\n\t\t// All retries exhausted\n\t\tthrow new IllegalStateException(\n\t\t\t\tString.format(\"Failed to get valid decision after %d retries. Last invalid decision: %s\",\n\t\t\t\t\t\tmaxRetries, lastInvalidDecision));\n\t}\n\n\t/**\n\t * Response record for structured routing decision output\n\t */\n\tpublic record RoutingDecision(String agent) { }\n}\n","sourceCodeStart":218,"sourceCodeEnd":246,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/flow/node/RoutingEdgeAction.java#L218-L246","documentation":"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.","triggerScenarios":"The routing LLM repeatedly returns responses that fail decision parsing/validation for maxRetries attempts while RoutingAgent evaluates its edge action.","commonSituations":"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.","solutions":["Use a model that reliably follows the structured routing format (or enable structured output) for the router","Check the lastInvalidDecision in the message and fix the routing prompt/schema so its output parses","Verify the agent names the router can return match the registered sub-agents","Increase maxRetries or configure a fallback decision if supported"],"exampleFix":"// before\nRoutingAgent.builder().model(weakModel).subAgents(a, b).build();\n// after\nRoutingAgent.builder().model(structuredOutputModel)\n    .subAgents(a, b)\n    .fallbackAgent(defaultAgent) // or validate prompt format\n    .build();","handlingStrategy":"retry","validationCode":"// pre-validate: ensure router model supports structured output and sub-agent names are registered\nSet<String> valid = subAgents.stream().map(Agent::name).collect(java.util.stream.Collectors.toSet());","typeGuard":"boolean isParsableDecision(String raw, Set<String> validAgents) { return raw != null && validAgents.contains(raw.trim()); }","tryCatchPattern":"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; }","preventionTips":["Use a structured-output-capable model for routing","Keep routing prompts explicit about the allowed decisions","Monitor lastInvalidDecision in logs to tune prompts","Configure a fallback route"],"tags":["routing","llm","retries-exhausted"],"backgroundTag":"unexpected-response-shape","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}