quarkusio/quarkus · error · IllegalArgumentException

`timestamp` must not be `null`

Error message

`timestamp` must not be `null`

What it means

GetExArgs.exAt(Instant) converts an Instant to POSIX seconds for the GETEX EXAT option; it requires a non-null Instant. Passing null would cause a downstream NPE, so the method fails fast with this IllegalArgumentException.

Source

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

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

    /**
     * Sets the expiration time
     *
     * @param timestamp the timestamp type: posix time in seconds.
     * @return the current {@code GetExArgs}
     */
    public GetExArgs exAt(Instant timestamp) {
        if (timestamp == null) {
            throw new IllegalArgumentException("`timestamp` must not be `null`");
        }
        exAt(timestamp.toEpochMilli() / 1000);
        return this;
    }

    /**
     * Set the specified expire time, in milliseconds.
     *
     * @param timeout expire time in milliseconds.
     * @return the current {@code GetExArgs}
     */
    public GetExArgs px(long timeout) {
        this.px = timeout;
        return this;
    }

    /**
     * Set the specified expire time, in milliseconds.

View on GitHub (pinned to e1c734241f)

Solutions

  1. Pass a concrete non-null Instant, e.g. exAt(Instant.now().plusSeconds(3600))
  2. Guard with a null check and either skip exAt or use persist()/a relative ex(Duration) instead
  3. Use Instant.now() or a defaulted value when the source timestamp is absent

Example fix

// before
Instant expiry = null;
args.exAt(expiry);
// after
Instant expiry = computeExpiry();
if (expiry == null) {
    expiry = Instant.now().plusSeconds(3600);
}
args.exAt(expiry);
Defensive patterns

Strategy: validation

Validate before calling

if (timestamp == null) {
    throw new IllegalArgumentException("Expiry timestamp must be provided for GETEX exAt()");
}

Type guard

boolean hasExpiry(Instant i) {
    return i != null && i.isAfter(Instant.now());
}

Try / catch

try {
    redis.string().getex(key, new GetExArgs().exAt(expiry));
} catch (IllegalArgumentException e) {
    log.warn("GETEX skipped: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling GetExArgs.exAt((Instant) null) — commonly with a computed timestamp variable that is null, e.g. Instant expiry = optional.map(...).orElse(null) followed by exAt(expiry) while building getex args.

Common situations: Optional expiration timestamps from scheduling/lookup logic returning null; uninitialized fields used as the expiry; refactors where a fallback Instant was dropped.

Related errors


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