spring-projects/spring-ai · error · IllegalStateException

Both or none of `maxIdleConnections` and `keepAliveDuration`

Error message

Both or none of `maxIdleConnections` and `keepAliveDuration` must be set, but only one was set

What it means

The SpringAiAnthropicHttpClient.Builder's build() validates that the OkHttp connection-pool tuning options are set as a pair. If exactly one of maxIdleConnections or keepAliveDuration was provided, it throws IllegalStateException, because a ConnectionPool requires both values and a half-specified pool is a configuration mistake.

Source

Thrown at models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/http/okhttp/SpringAiAnthropicHttpClient.java:637

							toHttpResponse(response));
					return authed.map(req -> toRequestComputeUrl(req, null)).orElse(null);
				});
			}

			ExecutorService userDispatcherExecutor = this.dispatcherExecutorService;
			boolean ownsDispatcherExecutor = userDispatcherExecutor == null;
			ExecutorService dispatcherBase = (userDispatcherExecutor != null) ? userDispatcherExecutor
					: defaultDispatcherExecutor();
			ExecutorService dispatcherExecutor = ContextExecutorService.wrap(dispatcherBase,
					ContextSnapshotFactory.builder().build());
			okBuilder.dispatcher(new Dispatcher(dispatcherExecutor));

			if (this.maxIdleConnections != null && this.keepAliveDuration != null) {
				okBuilder.connectionPool(new ConnectionPool(this.maxIdleConnections, this.keepAliveDuration.toNanos(),
						TimeUnit.NANOSECONDS));
			}
			else if ((this.maxIdleConnections == null) != (this.keepAliveDuration == null)) {
				throw new IllegalStateException(
						"Both or none of `maxIdleConnections` and `keepAliveDuration` must be set, but only one was set");
			}

			if (this.sslSocketFactory != null && this.trustManager != null) {
				okBuilder.sslSocketFactory(this.sslSocketFactory, this.trustManager);
			}
			else if ((this.sslSocketFactory == null) != (this.trustManager == null)) {
				throw new IllegalStateException(
						"Both or none of `sslSocketFactory` and `trustManager` must be set, but only one was set");
			}

			if (this.hostnameVerifier != null) {
				okBuilder.hostnameVerifier(this.hostnameVerifier);
			}

			OkHttpClient okClient = okBuilder.build();
			// Same-host traffic: raise per-host limit to overall request limit. Matches
			// the SDK's tuning at the bottom of `OkHttpClient.Builder.build()`.

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Set both values together: .maxIdleConnections(n).keepAliveDuration(Duration.ofMinutes(5)).
  2. If tuning is not needed, remove both settings and use OkHttp's default pool.
  3. Review your configuration binding so that the two properties are always applied as a unit (e.g. a single ConnectionPool config object).

Example fix

// before
SpringAiAnthropicHttpClient.newBuilder().maxIdleConnections(5).build(); // throws
// after
SpringAiAnthropicHttpClient.newBuilder()
    .maxIdleConnections(5)
    .keepAliveDuration(Duration.ofMinutes(5))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

static void checkPoolConfig(Integer maxIdle, Duration keepAlive) {
    if ((maxIdle == null) != (keepAlive == null)) {
        throw new IllegalStateException("maxIdleConnections and keepAliveDuration must both be set or both null");
    }
}

Try / catch

try {
    return SpringAiAnthropicHttpClient.newBuilder()...build();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("maxIdleConnections")) {
        // fall back to defaults or apply both settings
    }
    throw e;
}

Prevention

When it happens

Trigger: Building the client with only maxIdleConnections set, or only keepAliveDuration set, e.g. clientBuilder().maxIdleConnections(5).build().

Common situations: Copying a tuning snippet from docs and setting one field; conditional configuration code that sets one property but not the other; refactoring that dropped one of the two builder calls.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/da1683f054ee79d8. Report an issue: GitHub.