quarkusio/quarkus · error · IllegalArgumentException
Only one value from `GT`, `LT` and `NX` can be set
Error message
Only one value from `GT`, `LT` and `NX` can be set
What it means
ExpireArgs builds extra arguments for EXPIRE/PEXPIRE/EXPIREAT/PEXPIREAT. Redis allows at most one of the NX, GT, LT exclusion conditions per call; the client detects two or more of these flags (here NX combined with LT, or LT combined with GT) in toArgs() and throws IllegalArgumentException before sending the command. XX is tracked separately and not part of this check.
Source
Thrown at extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/keys/ExpireArgs.java:71
public ExpireArgs gt() {
this.gt = true;
return this;
}
public List<Object> toArgs() {
List<Object> args = new ArrayList<>();
boolean exclusion = false;
if (nx) {
args.add("NX");
exclusion = true;
}
if (xx) {
args.add("XX");
}
if (lt) {
if (exclusion) {
throw new IllegalArgumentException("Only one value from `GT`, `LT` and `NX` can be set");
}
exclusion = true;
args.add("LT");
}
if (gt) {
if (exclusion) {
throw new IllegalArgumentException("Only one value from `GT`, `LT` and `NX` can be set");
}
args.add("GT");
}
return args;
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Keep at most one of nx(), gt(), or lt() on the ExpireArgs instance
- Validate your option set before constructing ExpireArgs if flags come from external input
- XX may be combined with one exclusion flag — if you need XX, keep it and drop the extra exclusions
- Choose the intended precedence (e.g. prefer nx over lt) and build only that flag
Example fix
// before ExpireArgs args = new ExpireArgs().nx().lt(); // throws // after ExpireArgs args = new ExpireArgs().lt(); // only one of NX/GT/LT // or with XX if allowed: ExpireArgs args2 = new ExpireArgs().xx().lt();
Defensive patterns
Strategy: validation
Validate before calling
int exclusions = (useNx ? 1 : 0) + (useGt ? 1 : 0) + (useLt ? 1 : 0);
if (exclusions > 1) {
throw new IllegalArgumentException("At most one of NX, GT, LT may be set for EXPIRE");
}
ExpireArgs args = new ExpireArgs();
if (useXx) args.xx();
if (useNx) args.nx();
else if (useGt) args.gt();
else if (useLt) args.lt(); Try / catch
try {
keys.pexpireat(key, timestamp, args);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("GT`, `LT` and `NX")) {
// rebuild ExpireArgs with a single exclusion flag
}
} Prevention
- Count nx/gt/lt flags before building ExpireArgs; allow at most one
- Remember XX can be combined with one of NX/GT/LT but never two exclusions
- Centralize expiry-args construction in a utility that validates flag combinations
When it happens
Trigger: Chaining multiple exclusion flags on ExpireArgs, e.g. new ExpireArgs().nx().lt() or .lt().gt(), then passing it to a keys datasource _pexpireat/_expire call.
Common situations: Accumulating expiry options from config or user input where more than one of nx/gt/lt is enabled; copy-pasted builder chains; generic option-mapping code that applies every non-default flag.
Related errors
- Cannot set XX and NX together
- Cannot use `ON HASH` and `ON JSON` at the same time
- Cannot use descending and ascending order at the same time
- The Reactive Redis Client must be injected
- `count` must be strictly positive
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/49204205d3b5d5c1.
Report an issue: GitHub.