{"record":{"id":"735d5983980769a7","repo":"alibaba/spring-ai-alibaba","slug":"failed-to-get-valid-decision-after-d-retries-las-735d59","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/RoutingNode.java","lineNumber":279,"sourceCode":"\t\t\t\t\t\t\t\trootAgent.name(), attempt, maxRetries, invalidAgents);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlastInvalidDecision = Collections.emptyList();\n\t\t\t\t\tlogger.warn(\"RoutingAgent {} attempt {}/{} returned empty agent list\",\n\t\t\t\t\t\t\trootAgent.name(), attempt, maxRetries);\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\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\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 * Each agent has a targeted sub-question optimized for that agent's capabilities.\n\t */\n\tpublic static class RoutingDecision {\n\t\tprivate List<AgentRouting> agents;\n\n\t\tpublic RoutingDecision() {\n\t\t\tthis.agents = new ArrayList<>();\n\t\t}\n\n\t\tpublic RoutingDecision(List<AgentRouting> agents) {\n\t\t\tthis.agents = agents != null ? agents : Collections.emptyList();\n\t\t}","sourceCodeStart":261,"sourceCodeEnd":297,"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/RoutingNode.java#L261-L297","documentation":"RoutingAgent's retry loop failed to obtain a structurally valid routing decision from the LLM after exhausting maxRetries attempts. The library throws IllegalStateException because routing cannot proceed without a decision; lastInvalidDecision records the final rejected output for debugging. This is a fail-fast guard around non-deterministic LLM structured output.","triggerScenarios":"Calling RoutingAgent (via apply -> getDecisionWithRetry) when the underlying model repeatedly returns a routing decision that fails validation (e.g. wrong branch key, malformed structured output, missing required decision fields) on every attempt up to maxRetries.","commonSituations":"Model not honoring the structured-output schema (weak model or no JSON mode), router prompt listing branch names that don't match the registered conditional agents, response truncated by a low maxTokens setting, or transient provider errors consuming all retries.","solutions":["Inspect lastInvalidDecision in the exception message and fix the router prompt/schema so valid decisions are produced","Verify the decision keys returned by the model exactly match the condition keys registered in the routing/conditional mapping","Use a model with native structured output / JSON mode and increase maxTokens to avoid truncation","Increase maxRetries or wrap the call with an application-level fallback route (default branch)","Check provider health/quota if the log line 'encountered an error, will retry' repeats with transport errors"],"exampleFix":"// before\nRoutingAgent agent = RoutingAgent.builder().model(weakModel).build();\n// after\nRoutingAgent agent = RoutingAgent.builder()\n    .model(structuredOutputModel)\n    .maxRetries(5)\n    .build();","handlingStrategy":"retry","validationCode":"if (decision == null || !validBranchKeys.contains(decision)) throw new IllegalStateException(\"Router returned invalid decision: \" + decision);","typeGuard":"static boolean isValidDecision(String d, Set<String> keys) { return d != null && keys.contains(d); }","tryCatchPattern":"try { return routingAgent.apply(state); } catch (IllegalStateException e) { log.warn(\"Routing failed: {}\", e.getMessage()); return defaultRoute; }","preventionTips":["Use a model with native structured output support for the router","Keep branch keys in one shared constant set used by both prompt and validation","Set maxTokens high enough to avoid truncated decisions","Add a deterministic default/fallback branch"],"tags":["llm","routing","retry-exhausted","structured-output"],"backgroundTag":"unexpected-api-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"}