alibaba/spring-ai-alibaba · error · IllegalArgumentException

maxRetries must be >= 0

Error message

maxRetries must be >= 0

What it means

ToolRetryInterceptor's deprecated Builder.maxRetries(int) validates that the retry count is non-negative, throwing IllegalArgumentException when a negative value is passed. maxRetries counts extra retries, so total attempts = maxRetries + 1. The library rejects negative numbers because a negative retry count is meaningless.

Source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/toolretry/ToolRetryInterceptor.java:195

		 * @param maxAttempts total attempts (initial call plus retries)
		 */
		public Builder maxAttempts(int maxAttempts) {
			if (maxAttempts < 1) {
				throw new IllegalArgumentException("maxAttempts must be >= 1");
			}
			this.maxAttempts = maxAttempts;
			return this;
		}

		/**
		 * Set the maximum number of retries (excluding the first call).
		 * @param maxRetries number of retries; total attempts will be {@code maxRetries + 1}
		 * @deprecated use {@link #maxAttempts(int)} instead, which counts the initial call
		 */
		@Deprecated
		public Builder maxRetries(int maxRetries) {
			if (maxRetries < 0) {
				throw new IllegalArgumentException("maxRetries must be >= 0");
			}
			this.maxAttempts = maxRetries + 1;
			return this;
		}

		public Builder toolNames(Set<String> toolNames) {
			this.toolNames = toolNames;
			return this;
		}

		public Builder toolName(String toolName) {
			if (this.toolNames == null) {
				this.toolNames = new HashSet<>();
			}
			this.toolNames.add(toolName);
			return this;
		}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Pass 0 to disable retries instead of a negative number
  2. Prefer the non-deprecated maxAttempts(int) builder method, which counts the initial call (total attempts = maxAttempts)
  3. Validate the configured value before building the interceptor

Example fix

// before
ToolRetryInterceptor.builder().maxRetries(-1).build();
// after
ToolRetryInterceptor.builder().maxAttempts(1).build(); // 1 total attempt, no retries
Defensive patterns

Strategy: validation

Validate before calling

if (retries < 0) throw new IllegalArgumentException("Configure retries >= 0, or use maxAttempts >= 1");

Type guard

boolean isValidRetryCount(int n) { return n >= 0; }

Try / catch

try { b.maxRetries(n); } catch (IllegalArgumentException e) { b.maxAttempts(Math.max(1, n + 1)); }

Prevention

When it happens

Trigger: Calling ToolRetryInterceptor.Builder.maxRetries(-1) (or any negative int) instead of using the replacement maxAttempts(int).

Common situations: Computing the retry count from config or environment variables that may be negative or uninitialized; migrating code and passing -1 as a sentinel for 'no retries' instead of 0.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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