{"record":{"id":"04d40b10a192d804","repo":"alibaba/spring-ai-alibaba","slug":"model-call-failed-attempted","errorCode":null,"errorMessage":"Model call failed (attempted {}/{}): {}","messagePattern":"Model call failed \\(attempted (.+?)/(.+?)\\): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/modelretry/ModelRetryInterceptor.java","lineNumber":130,"sourceCode":"\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else if (attempt >= maxAttempts) {\n\t\t\t\t\t\tlog.error(\"The maximum number of retries has been reached {}, and the model call has failed.\", maxAttempts);\n\t\t\t\t\t\tthrow new RuntimeException(\"Model call failed, maximum number of retries reached:\" + exceptionText);\n\t\t\t\t\t}\n\n\t\t\t\t\t// For non-retryable exceptions, return immediately.\n\t\t\t\t\treturn modelResponse;\n\t\t\t\t}\n\n\t\t\t\t// Successful response\n\t\t\t\tif (attempt > 1) {\n\t\t\t\t\tlog.info(\"The model call succeeded after the {}th attempt.\", attempt);\n\t\t\t\t}\n\t\t\t\treturn modelResponse;\n\n\t\t\t} catch (Exception e) {\n\t\t\t\tlastException = e;\n\t\t\t\tlog.warn(\"Model call failed (attempted {}/{}): {}\", attempt, maxAttempts, e.getMessage());\n\n\t\t\t\tif (attempt >= maxAttempts) {\n\t\t\t\t\tlog.error(\"The maximum number of retries has been reached {}, and the model call has failed.\", maxAttempts);\n\t\t\t\t\tthrow new RuntimeException(\"Model call failed, maximum number of retries reached.\", lastException);\n\t\t\t\t}\n\n\t\t\t\t// Determine if an exception can be retried.\n\t\t\t\tif (!retryableExceptionPredicate.test(e)) {\n\t\t\t\t\tlog.warn(\"Exceptions cannot be retried and are thrown immediately: {}\", e.getMessage());\n\t\t\t\t\tthrow new RuntimeException(\"Model call failed (non-retryable exception)\", e);\n\t\t\t\t}\n\n\t\t\t\t// Wait and try again\n\t\t\t\tif (currentDelay > 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlog.info(\"Retry after {} ms\", currentDelay);\n\t\t\t\t\t\tThread.sleep(currentDelay);\n\t\t\t\t\t} catch (InterruptedException ie) {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/modelretry/ModelRetryInterceptor.java#L112-L148","documentation":"ModelRetryInterceptor.interceptModel logs 'Model call failed (attempted N/max)' whenever the ChatModel call throws, records lastException, and either schedules a retry with backoff or — when attempt >= maxAttempts — throws RuntimeException('Model call failed, maximum number of retries reached.'). This is the per-attempt failure record for the retry loop.","triggerScenarios":"modelResponse = model.call(...) throws on any attempt: network errors, timeouts, 4xx/5xx from the provider, auth failures — retried until maxAttempts is consumed.","commonSituations":"Sustained provider outage (retries exhausted); persistent 401 from a bad API key (retrying is pointless); context length errors that will fail every attempt; maxAttempts set too low for a flaky network.","solutions":["Read the logged per-attempt message to classify the error before changing retry settings","Fix permanent errors (credentials, oversized prompt) directly — retries cannot help","Increase maxAttempts/backoff only for genuinely transient errors (timeouts, 429s)","Catch the final RuntimeException at the call site, or wrap the model in ModelFallbackInterceptor for a last-resort model switch","Verify retryablePredicate excludes non-retryable errors to fail fast"],"exampleFix":"// before\nModelRetryInterceptor.of(model); // throws after max retries, unhandled\n// after\nModelRetryInterceptor retry = ModelRetryInterceptor.builder()\n    .chatModel(model).maxAttempts(3)\n    .initialBackoff(Duration.ofMillis(500)).build();\ntry {\n    return retry.interceptModel(request, chain);\n} catch (RuntimeException e) {\n    return fallbackResponse(request); // graceful degradation\n}","handlingStrategy":"retry","validationCode":"if (promptTokensEstimate(messages) > modelContextLimit) { throw new IllegalArgumentException(\"Prompt too large for model; retrying cannot succeed\"); }","typeGuard":null,"tryCatchPattern":"try { return interceptor.interceptModel(request, chain); }\ncatch (RuntimeException e) {\n    if (e.getCause() instanceof AuthException) throw e; // don't mask permanent failures\n    return fallbackChain.interceptModel(request, chain);\n}","preventionTips":["Validate credentials and prompt size before invocation — retrying cannot fix them","Set maxAttempts (e.g. 3) with exponential backoff for transient errors only","Combine with ModelFallbackInterceptor so exhausted retries fall through to another model","Monitor per-attempt warn logs to distinguish flaky networks from outages"],"tags":["model","retry","interceptor","max-attempts"],"backgroundTag":"api-request-failed","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"}