alibaba/spring-ai-alibaba · error · IllegalArgumentException

recursionLimit must be > 0!

Error message

recursionLimit must be > 0!

What it means

CompileConfig.Builder.recursionLimit enforces a strictly positive recursion limit because graph execution uses it to cap the number of node transitions and prevent infinite loops. Passing 0 or a negative value throws IllegalArgumentException.

Source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/CompileConfig.java:182

	/**
	 * Builder class for creating instances of CompileConfig. It allows setting various
	 * options such as savers, interrupts, and lifecycle listeners in a fluent manner.
	 */
	public static class Builder {

		private final CompileConfig config;

		/**
		 * Initializes the builder with the provided compile configuration.
		 * @param config The base configuration to start from.
		 */
		protected Builder(CompileConfig config) {
			this.config = new CompileConfig(config);
		}

		public Builder recursionLimit(int recursionLimit) {
			if( recursionLimit <= 0 ) {
				throw new IllegalArgumentException("recursionLimit must be > 0!");
			}
			this.config.recursionLimit = recursionLimit;
			return this;
		}

		/**
		 * Sets whether the thread should be released during execution.
		 * @param releaseThread Flag indicating whether to release the thread.
		 * @see BaseCheckpointSaver#release(RunnableConfig)
		 * @return This builder instance for method chaining.
		 */
		public Builder releaseThread(boolean releaseThread) {
			this.config.releaseThread = releaseThread;
			return this;
		}

		/**
		 * Sets the observation registry for monitoring and tracing.

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Pass a positive integer (e.g. 25–50 for typical agent loops).
  2. Default the config value: int limit = configured > 0 ? configured : 25;
  3. Prefer CompileConfig.recursionLimit() over the deprecated CompiledGraph.setMaxIterations.

Example fix

// before
CompileConfig cfg = CompileConfig.builder().recursionLimit(0).build();
// after
CompileConfig cfg = CompileConfig.builder().recursionLimit(25).build();
Defensive patterns

Strategy: validation

Validate before calling

if (configuredLimit <= 0) configuredLimit = 25; CompileConfig cfg = CompileConfig.builder().recursionLimit(configuredLimit).build();

Type guard

Integer safeRecursionLimit(Integer v) { return (v == null || v <= 0) ? 25 : v; }

Try / catch

try { cfg = CompileConfig.builder().recursionLimit(n).build(); } catch (IllegalArgumentException e) { cfg = CompileConfig.builder().recursionLimit(25).build(); }

Prevention

When it happens

Trigger: Calling new CompileConfig.Builder().recursionLimit(0) or recursionLimit(negative), often from a config value that defaulted to 0 or was computed as -1.

Common situations: Loading recursion limit from application properties that were unset (0); arithmetic producing a non-positive value; copying a config object whose limit was never initialized.

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/51495e1005ad1806. Report an issue: GitHub.