quarkusio/quarkus · error · IllegalArgumentException

`timeout` must not be `null`

Error message

`timeout` must not be `null`

What it means

SetArgs.ex(Duration) converts the duration to seconds and delegates to ex(long), but first rejects a null Duration. The Quarkus Redis client validates arguments eagerly to fail at the call site rather than at Redis. Null cannot represent an expiry duration.

Source

Thrown at extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/string/SetArgs.java:49

     * @return the current {@code GetExArgs}
     */
    public SetArgs ex(long timeout) {
        if (timeout <= 0) {
            throw new IllegalArgumentException("`timeout` must be positive");
        }
        this.ex = timeout;
        return this;
    }

    /**
     * Sets the expiration.
     *
     * @param timeout expire time in seconds.
     * @return the current {@code GetExArgs}
     */
    public SetArgs ex(Duration timeout) {
        if (timeout == null) {
            throw new IllegalArgumentException("`timeout` must not be `null`");
        }
        return ex(timeout.toMillis() / 1000);
    }

    /**
     * Sets the expiration time
     *
     * @param timestamp the timestamp
     * @return the current {@code GetExArgs}
     */
    public SetArgs exAt(long timestamp) {
        this.exAt = timestamp;
        return this;
    }

    /**
     * Sets the expiration time
     *

View on GitHub (pinned to e1c734241f)

Solutions

  1. Provide a default: ex(duration != null ? duration : Duration.ofSeconds(60))
  2. Build args conditionally and skip ex() when duration == null
  3. Switch to the long-based ex(long seconds) only after the duration has been resolved and null-checked

Example fix

// before
Duration ttl = config.ttl(); // may be null
SetArgs args = SetArgs.args().ex(ttl); // throws

// after
Duration ttl = config.ttl();
SetArgs args = ttl != null
    ? SetArgs.args().ex(ttl)
    : SetArgs.args();
Defensive patterns

Strategy: validation

Validate before calling

if (ttl == null || ttl.isZero() || ttl.isNegative()) {
    throw new IllegalArgumentException("TTL duration must be non-null and positive");
}
SetArgs.args().ex(ttl);

Type guard

boolean isPositiveDuration(Duration d) {
    return d != null && !d.isZero() && !d.isNegative();
}

Try / catch

try {
    args.ex(duration);
} catch (IllegalArgumentException e) {
    if (!e.getMessage().contains("`timeout` must not be `null`")) throw e;
    args = SetArgs.args(); // skip expiry
}

Prevention

When it happens

Trigger: Calling SetArgs ex(null), commonly when a Duration is read from optional configuration (e.g. ConfigProvider or Optional<Duration>) and not defaulted.

Common situations: Config property quarkus.redis-style TTL is absent, producing a null Duration; or a method parameter of type Duration is optional and the caller passes null to signal 'no expiry'.

Understand the failure class

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/f935a407b2a0a100. Report an issue: GitHub.