TheAlgorithms/Java · error · IllegalArgumentException

Default TTL must be >= 0

Error message

Default TTL must be >= 0

What it means

Thrown by LIFOCache.Builder.defaultTTL(long) when ttlMillis is negative. The default TTL is applied to entries added without an explicit TTL; a negative value sets their expiry in the past. The check runs before storing the field.

Source

Thrown at src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java:518

         * @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 an eviction listener to be notified when entries are evicted from the cache.
         *
         * @param listener a {@link BiConsumer} that accepts evicted keys and values; must not be {@code null}
         * @return this builder instance for chaining
         * @throws IllegalArgumentException if {@code listener} is {@code null}
         */
        public Builder<K, V> evictionListener(BiConsumer<K, V> listener) {
            if (listener == null) {
                throw new IllegalArgumentException("Listener must not be null");
            }
            this.evictionListener = listener;
            return this;

View on GitHub (pinned to fdfb9a395b)

Solutions

  1. Clamp the value: builder.defaultTTL(Math.max(0, configuredTtl)).
  2. Treat negative config as 'no expiry' explicitly, or reject at startup.
  3. Add startup assertions on all TTL config keys.

Example fix

// before
builder.defaultTTL(props.getTtlMillis());
// after
long ttl = props.getTtlMillis();
builder.defaultTTL(ttl < 0 ? 0 : ttl);
Defensive patterns

Strategy: validation

Validate before calling

long ttl = configuredDefaultTtl;
builder.defaultTTL(ttl < 0 ? 0 : ttl);

Type guard

static boolean isValidDefaultTtl(long ttlMillis) {
    return ttlMillis >= 0;
}

Prevention

When it happens

Trigger: builder.defaultTTL(-1); defaultTTL from a negative Duration; config typo with a leading minus; clock-skew arithmetic.

Common situations: Env config (cache.defaultTtl=-60000) typoed; duration from skewed clocks; reused negated variable.

Related errors


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