quarkusio/quarkus · error · IllegalArgumentException

`timestamp` must not be `null`

Error message

`timestamp` must not be `null`

What it means

SetArgs.exAt(Instant) sets the EXAT (unix expiry in seconds) option for a Redis SET command and rejects a null Instant. The client validates eagerly so the error surfaces at the call site with a clear message instead of a malformed Redis command. Null has no valid epoch representation.

Source

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

     * 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
     *
     * @param timestamp the timestamp type: posix time in seconds.
     * @return the current {@code GetExArgs}
     */
    public SetArgs 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 SetArgs px(long timeout) {
        if (timeout < 0) {
            throw new IllegalArgumentException("`timeout` must be positive");
        }
        this.px = timeout;
        return this;
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Skip exAt() when the timestamp is null: build SetArgs conditionally
  2. Default the Instant, e.g. Instant.now().plus(configuredTtl), when absence should mean a default expiry
  3. Use ex()/px() duration-based variants when an absolute timestamp is not actually required

Example fix

// before
Instant expiresAt = record.getExpiresAt(); // may be null
SetArgs args = SetArgs.args().exAt(expiresAt); // throws

// after
Instant expiresAt = record.getExpiresAt();
SetArgs args = expiresAt != null
    ? SetArgs.args().exAt(expiresAt)
    : SetArgs.args();
Defensive patterns

Strategy: validation

Validate before calling

if (expiresAt == null) {
    throw new IllegalStateException("expiresAt is required for exAt; use ex()/px() for relative TTL");
}
SetArgs.args().exAt(expiresAt);

Type guard

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

Try / catch

try {
    args.exAt(timestamp);
} catch (IllegalArgumentException e) {
    if (!e.getMessage().contains("`timestamp` must not be `null`")) throw e;
    args = SetArgs.args(); // proceed without EXAT
}

Prevention

When it happens

Trigger: Calling SetArgs exAt(null), typically from a nullable Instant field (e.g. 'expiresAt' column null for never-expiring records) passed without a check.

Common situations: Mapping an entity whose optional expiration timestamp is null into cache-set logic; or refactoring code where the timestamp became optional but the args-building code was not updated.

Related errors


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