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

  1. Convert the key with key.toString() or SafeEncoder.encode(key) before passing it.
  2. For xread/xreadGroup, ensure the first argument is the stream key (String/byte[]) and the StreamEntryID is passed in the expected map/parameter position.
  3. 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

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


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)