TheAlgorithms/Java · error · IllegalArgumentException

Default TTL must be >= 0

Error message

Default TTL must be >= 0

What it means

Builder.defaultTTL() rejects negative values. The default TTL is applied to entries inserted via the two-argument put(key, value) method. A value of 0 means entries never expire.

Source

Thrown at src/main/java/com/thealgorithms/datastructures/caches/RRCache.java:445

         * @throws IllegalArgumentException if {@code capacity} is less than or equal to 0
         */
        public Builder(int capacity) {
            if (capacity <= 0) {
                throw new IllegalArgumentException("Capacity must be > 0");
            }
            this.capacity = capacity;
        }

        /**
         * Sets the default time-to-live (TTL) in milliseconds for cache entries.
         *
         * @param ttlMillis the TTL duration in milliseconds; must be >= 0
         * @return this builder instance for chaining
         * @throws IllegalArgumentException if {@code ttlMillis} is negative
         */
        public Builder<K, V> defaultTTL(long ttlMillis) {
            if (ttlMillis < 0) {
                throw new IllegalArgumentException("Default TTL must be >= 0");
            }
            this.defaultTTL = ttlMillis;
            return this;
        }

        /**
         * Sets the {@link Random} instance to be used for random eviction selection.
         *
         * @param r a non-null {@code Random} instance
         * @return this builder instance for chaining
         * @throws IllegalArgumentException if {@code r} is {@code null}
         */
        public Builder<K, V> random(Random r) {
            if (r == null) {
                throw new IllegalArgumentException("Random must not be null");
            }
            this.random = r;
            return this;

View on GitHub (pinned to fdfb9a395b)

Solutions

  1. Clamp to Math.max(0, ttl) or simply omit the call to use the default of 0
  2. Validate TTL configuration before passing it to the builder
  3. Use 0 explicitly to indicate no expiry

Example fix

// before
.long defaultTtl = Duration.parse(config.get("ttl")).toMillis(); // can be negative on bad input
new RRCache.Builder<String,String>(100).defaultTTL(defaultTtl).build();

// after
long defaultTtl = Duration.parse(config.getOrDefault("ttl", "PT0S")).toMillis();
new RRCache.Builder<String,String>(100).defaultTTL(Math.max(0, defaultTtl)).build();
Defensive patterns

Strategy: validation

Validate before calling

long ttl = Math.max(0, configuredDefaultTTL);
new RRCache.Builder<String,String>(100).defaultTTL(ttl).build();

Try / catch

try {
    builder.defaultTTL(ttlMillis);
} catch (IllegalArgumentException e) {
    builder.defaultTTL(0); // no-expiry fallback
}

Prevention

When it happens

Trigger: Calling builder.defaultTTL(-1) or any negative value during cache construction.

Common situations: TTL sourced from a duration config that can be negative. Unit conversion (e.g., seconds to millis) where a misconfigured value produces a negative result.

Related errors


AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13). Data as JSON: /api/errors/a4b32ccb2985b348. Report an issue: GitHub.