quarkusio/quarkus · error · IllegalArgumentException
`timeout` must be positive
Error message
`timeout` must be positive
What it means
SetArgs.ex(long) sets the EXPIRE (seconds) option for Redis SET commands. The Quarkus Redis datasource validates arguments eagerly and throws IllegalArgumentException when timeout <= 0, since a non-positive expiration is meaningless to Redis and almost always indicates a caller bug (e.g. a zeroed or miscomputed value).
Source
Thrown at extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/value/SetArgs.java:32
private long ex = -1;
private long exAt = -1;
private long px = -1;
private long pxAt = -1;
private boolean nx;
private boolean keepttl;
private boolean xx;
private boolean get;
/**
* Set the expiration timeout, in seconds.
*
* @param timeout expiration timeout in seconds
* @return the current {@code SetArgs}
*/
public SetArgs ex(long timeout) {
if (timeout <= 0) {
throw new IllegalArgumentException("`timeout` must be positive");
}
this.ex = timeout;
return this;
}
/**
* Set the expiration timeout, in seconds.
*
* @param timeout expiration timeout in seconds
* @return the current {@code SetArgs}
*/
public SetArgs ex(Duration timeout) {
if (timeout == null) {
throw new IllegalArgumentException("`timeout` must not be `null`");
}
return ex(timeout.toSeconds());
}
View on GitHub (pinned to e1c734241f)
Solutions
- Ensure the timeout passed to ex(long) is >= 1 second before building the SetArgs.
- If the intended TTL is sub-second, use px(Duration) / px(long) instead (milliseconds).
- Check the config value or computation feeding the TTL; guard against 0/negative defaults.
Example fix
// before SetArgs args = new SetArgs().ex(ttlMillis / 1000); // 500ms -> 0 -> throws // after SetArgs args = new SetArgs().px(Duration.ofMillis(ttlMillis));
Defensive patterns
Strategy: validation
Validate before calling
if (ttlSeconds <= 0) {
throw new IllegalArgumentException("TTL must be at least 1 second, got: " + ttlSeconds);
}
SetArgs args = new SetArgs().ex(ttlSeconds); Type guard
static boolean isValidExTimeout(long timeout) {
return timeout > 0;
} Try / catch
try {
args = new SetArgs().ex(ttlSeconds);
} catch (IllegalArgumentException e) {
log.warn("Invalid SET expiration " + ttlSeconds + ", defaulting to 60s");
args = new SetArgs().ex(60);
} Prevention
- Validate TTL values at the configuration boundary before they reach Redis calls.
- Use Duration types and px() for sub-second TTLs to avoid truncation to 0.
- Add unit tests covering zero and negative TTL inputs.
When it happens
Trigger: Calling SetArgs.ex(0), SetArgs.ex(-1), or any ex(long) with a value <= 0, directly or via any value API that accepts SetArgs (e.g. RedisValueCommands.set(key, value, args)).
Common situations: Passing a computed TTL that evaluates to 0 because of unit-conversion mistakes (e.g. ms-to-seconds truncation of sub-second values), uninitialized config defaults of 0, or misreading the parameter as milliseconds.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- ANY can only be used if COUNT is also set
- `radius` must be positive
- `width` must be positive
- `height` must be positive
- ANY can only be used if COUNT is also set
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/3dbf9a87b293d967.
Report an issue: GitHub.