{"record":{"id":"cde343dc395f2de2","repo":"alibaba/spring-ai-alibaba","slug":"maxattempts-must-be-greater-than-or-equal-to-1","errorCode":null,"errorMessage":"maxAttempts must be greater than or equal to 1","messagePattern":"maxAttempts must be greater than or equal to 1","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/modelretry/ModelRetryInterceptor.java","lineNumber":300,"sourceCode":"\t@Override\n\tpublic String getName() {\n\t\treturn \"ModelRetry\";\n\t}\n\n\tpublic static class Builder {\n\t\tprivate int maxAttempts = 3;\n\t\tprivate long initialDelay = 1000;\n\t\tprivate long maxDelay = 30000;\n\t\tprivate double backoffMultiplier = 2.0;\n\t\tprivate Predicate<Exception> retryableExceptionPredicate = Builder::isRetryableException;\n\n\t\t/**\n\t\t * Set the maximum number of retries (including the first call).\n\t\t * @param maxAttempts The maximum number of attempts must be >= 1.\n\t\t */\n\t\tpublic Builder maxAttempts(int maxAttempts) {\n\t\t\tif (maxAttempts < 1) {\n\t\t\t\tthrow new IllegalArgumentException(\"maxAttempts must be greater than or equal to 1\");\n\t\t\t}\n\t\t\tthis.maxAttempts = maxAttempts;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Set the initial retry delay (milliseconds).\n\t\t * @param initialDelay Initial delay time, in milliseconds\n\t\t */\n\t\tpublic Builder initialDelay(long initialDelay) {\n\t\t\tif (initialDelay < 0) {\n\t\t\t\tthrow new IllegalArgumentException(\"initialDelay must be greater than or equal to 0.\");\n\t\t\t}\n\t\t\tthis.initialDelay = initialDelay;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**","sourceCodeStart":282,"sourceCodeEnd":318,"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#L282-L318","documentation":"ModelRetryInterceptor.Builder.maxAttempts(int) validates that the maximum attempt count is at least 1 (the count includes the first call). Passing 0 or a negative value throws IllegalArgumentException at builder time, before any model call happens.","triggerScenarios":"Calling ModelRetryInterceptor.builder().maxAttempts(0) or maxAttempts(negative) — commonly from an external config value (properties file, env var) that is unset, 0, or mis-parsed.","commonSituations":"Binding maxAttempts from application.properties/yaml where a 'retries: 0' convention was assumed; integer parse failures defaulting to 0; arithmetic producing a negative value; thinking the setting means 'extra retries' rather than total attempts.","solutions":["Pass a value >= 1; remember 1 means the initial call with no retries, 3 means up to 2 retries.","Clamp or validate configuration at startup: Math.max(1, configuredMaxAttempts).","If you want retries disabled entirely, use maxAttempts(1) rather than 0."],"exampleFix":"// before\nint attempts = Integer.parseInt(props.getProperty(\"retry.maxAttempts\", \"0\"));\nModelRetryInterceptor.builder().maxAttempts(attempts).build();\n// after\nint attempts = Math.max(1, Integer.parseInt(props.getProperty(\"retry.maxAttempts\", \"3\")));\nModelRetryInterceptor.builder().maxAttempts(attempts).build();","handlingStrategy":"validation","validationCode":"public static ModelRetryInterceptor buildRetry(int maxAttempts) {\n    if (maxAttempts < 1) throw new IllegalArgumentException(\"maxAttempts must be >= 1 (1 = no retries)\");\n    return ModelRetryInterceptor.builder().maxAttempts(maxAttempts).build();\n}","typeGuard":null,"tryCatchPattern":"try {\n    builder.maxAttempts(cfg.maxAttempts());\n} catch (IllegalArgumentException e) {\n    log.warn(\"Invalid maxAttempts in config ({}), defaulting to 3\", cfg.maxAttempts());\n    builder.maxAttempts(3);\n}","preventionTips":["Remember the semantic: maxAttempts counts total attempts including the first; 1 disables retries.","Clamp external config values (Math.max(1, value)) before passing to the builder.","Cover builder configuration in unit tests so bad defaults surface in CI."],"tags":["builder","validation","configuration","retry"],"backgroundTag":"invalid-argument-value","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"}