alibaba/spring-ai-alibaba · error · IllegalArgumentException

ttlUnit cannot be null

Error message

ttlUnit cannot be null

What it means

RedisSaver.Builder.ttl(long, TimeUnit) validates that the time unit is provided. Passing null as ttlUnit throws IllegalArgumentException because a TTL without a unit is meaningless. The javadoc explicitly documents ttlUnit must not be null.

Source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/redis/RedisSaver.java:471

			this.stateSerializer = stateSerializer;
			return this;
		}

		/**
		 * Sets the time-to-live (TTL) for all Redis keys managed by RedisSaver.
		 * When set, checkpoint data, thread metadata, and reverse mappings will
		 * automatically expire after the specified duration.
		 * <p>
		 * Default is -1 (no expiration), which preserves backward compatibility.
		 *
		 * @param ttl the time-to-live value, must be positive; -1 means no expiration
		 * @param ttlUnit the time unit for ttl, must not be null
		 * @return this builder
		 * @throws IllegalArgumentException if ttlUnit is null or ttl is 0 or less than -1
		 */
		public Builder ttl(long ttl, TimeUnit ttlUnit) {
			if (ttlUnit == null) {
				throw new IllegalArgumentException("ttlUnit cannot be null");
			}
			if (ttl == 0 || ttl < -1) {
				throw new IllegalArgumentException("ttl must be positive or -1 (no expiration), got: " + ttl);
			}
			this.ttl = ttl;
			this.ttlUnit = ttlUnit;
			return this;
		}

		/**
		 * Builds a new RedisSaver instance.
		 * @return a new RedisSaver instance
		 * @throws IllegalArgumentException if redisson or stateSerializer is null
		 */
		public RedisSaver build() {
			if (redisson == null) {
				throw new IllegalArgumentException("redisson cannot be null");
			}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Pass an explicit TimeUnit, e.g. ttl(60, TimeUnit.SECONDS).
  2. If the unit comes from configuration, default it when absent (SECONDS) before calling the builder.
  3. Validate the configured unit string with TimeUnit.valueOf(...) inside a null check before building the saver.

Example fix

// before
Builder b = new RedisSaver.Builder().ttl(cfg.getTtl(), cfg.getUnit()); // getUnit() == null
// after
TimeUnit unit = cfg.getUnit() != null ? cfg.getUnit() : TimeUnit.SECONDS;
Builder b = new RedisSaver.Builder().ttl(cfg.getTtl(), unit);
Defensive patterns

Strategy: validation

Validate before calling

if (ttlUnit == null) {
    throw new IllegalStateException("redis checkpoint ttlUnit must be configured (e.g. SECONDS)");
}
saverBuilder.ttl(ttl, ttlUnit);

Prevention

When it happens

Trigger: new RedisSaver.Builder().ttl(60, null).build() — any builder chain that calls ttl() with a null TimeUnit, typically from a config mapping where the unit is read from properties and missing.

Common situations: Mapping YAML/properties config where only the numeric ttl is set and the unit key is absent; calling ttl(ttlValue, ttlUnitMap.get("unit")) returning null; refactoring code that dropped the constant TimeUnit argument.

Related errors


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