redis/jedis · error · IllegalArgumentException
" " is not a valid argument.
Error message
"${key.toString()}" is not a valid argument. What it means
CommandArguments.key(Object) converts a command's key into wire bytes but only supports byte[], String, and Rawable key objects. Any other object type passed as a key is rejected with an IllegalArgumentException that echoes the object's toString().
Solutions
- Convert the key with key.toString() or SafeEncoder.encode(key) before passing it.
- For xread/xreadGroup, ensure the first argument is the stream key (String/byte[]) and the StreamEntryID is passed in the expected map/parameter position.
- If the key is a domain object, add a method returning its Redis key string and use that.
Example fix
// before jedis.xread(mapOf(entryId, streamKeyObject)); // wrong type in key position // after Map<String, StreamEntryID> streams = new HashMap<>(); streams.put(streamKeyObject.toString(), entryId); jedis.xread(streams, XReadParams.xReadParams().block(1000));
Defensive patterns
Strategy: type-guard
Validate before calling
static String asRedisKey(Object key) {
if (key instanceof String) return (String) key;
if (key instanceof byte[]) return SafeEncoder.encode((byte[]) key);
if (key == null) throw new IllegalArgumentException("key is null");
return key.toString();
} Type guard
static boolean isValidKey(Object k) {
return k instanceof String || k instanceof byte[] || k instanceof redis.clients.jedis.args.Rawable;
} Try / catch
try {
jedis.xread(streams, params);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("is not a valid argument")) {
// rebuild with keys converted via asRedisKey()
} else throw e;
} Prevention
- Pass stream names as plain Strings to xread/xreadGroup.
- Keep StreamEntryID values in the ID parameter/map, never in the key position.
- Normalize keys through a single helper before any command call.
When it happens
Trigger: Calling stream commands such as xread/xreadGroup (which pass keys into CommandArguments.key) with a key that is not byte[], String, or Rawable — e.g. a StreamEntryID, a numeric ID, or a custom key object.
Common situations: Passing a stream name wrapped in a custom type; accidentally passing a StreamEntryID or Map entry where the stream key string was expected; framework code interpolating keys as non-String objects.
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.
Related errors
- Unsupported key type
- null is not a valid argument.
- is not a valid ZRANGE type argument.
- Unknown stream entry deletion result code
- Stream entry deletion result value cannot be null
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/b17fbd7671cb06e9.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/CommandArguments.java:148
if (keyPreProc != null) {
key = keyPreProc.actualKey(key);
}
if (key instanceof Rawable) {
Rawable raw = (Rawable) key;
args.add(raw);
// Extract raw bytes for hash slot computation to avoid ClassCastException in getKeyHashSlots()
addHashSlotKey(raw.getRaw());
} else if (key instanceof byte[]) {
byte[] raw = (byte[]) key;
args.add(RawableFactory.from(raw));
addHashSlotKey(raw);
} else if (key instanceof String) {
String raw = (String) key;
args.add(RawableFactory.from(raw));
addHashSlotKey(raw);
} else {
throw new IllegalArgumentException("\"" + key.toString() + "\" is not a valid argument.");
}
return this;
}
final CommandArguments addHashSlotKey(String key) {
keys.add(key);
// Invalidate cached hash slots since keys have changed
cachedHashSlots = null;
return this;
}
final CommandArguments addHashSlotKey(byte[] key) {
keys.add(key);
// Invalidate cached hash slots since keys have changed
cachedHashSlots = null;
return this;
}View on GitHub (pinned to 6dac31d4c2)