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
- Skip exAt() when the timestamp is null: build SetArgs conditionally
- Default the Instant, e.g. Instant.now().plus(configuredTtl), when absence should mean a default expiry
- 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
- Model optional expiries as Optional<Instant> and branch before building args
- Prefer relative ex()/px() when the value is derived from 'now + ttl' anyway
- Unit-test the null-timestamp path of cache-write code
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
- `timeout` must not be `null`
- `count` must be strictly positive
- `timeout` must be positive
- `timeout` must not be `null`
- `timestamp` must not be `null`
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f107231fe0c35cd7.
Report an issue: GitHub.