redis/jedis · error · IllegalArgumentException

Unsupported key type

Error message

Unsupported key type: ${preprocessedKey.getClass().getName()}

What it means

ClusterCommandObjects.calculateSlotFromPreprocessedKey computes the Redis Cluster hash slot for a key, but only understands byte[], String, and Rawable key representations. When a command is built with a key object of any other type, it cannot be routed to a cluster node, so an IllegalArgumentException is thrown naming the offending class.

Solutions

  1. Convert the key to a supported type before passing it: call key.toString(), SafeEncoder.encode(key), or implement redis.clients.jedis.args.Rawable returning the encoded bytes.
  2. If the key is a custom wrapper, extract the underlying String or byte[] representation at the call site.
  3. Check for a version/API change: ensure you are passing the raw key value, not a CommandObject or other internal type, to the command method.

Example fix

// before
cluster.set(myKeyWrapper, value); // myKeyWrapper is a custom type
// after
cluster.set(myKeyWrapper.toString(), value);
Defensive patterns

Strategy: type-guard

Validate before calling

private static Object toClusterKey(Object key) {
  if (key instanceof String || key instanceof byte[] || key instanceof redis.clients.jedis.args.Rawable) return key;
  return key.toString();
}

Type guard

static boolean isClusterKey(Object k) {
  return k instanceof String || k instanceof byte[] || k instanceof redis.clients.jedis.args.Rawable;
}

Try / catch

try {
  cluster.set(key, value);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Unsupported key type")) {
    cluster.set(key.toString(), value);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling any cluster command via UnifiedJedis/ClusterCommandObjects with a key argument that is neither byte[], String, nor a Rawable — e.g. a custom key wrapper object, an Integer/Long passed where a key is expected, or a CommandObject built with an unsupported preprocessed key type.

Common situations: Migrating code from a standalone Jedis setup to RedisClusterClient where keys were passed as arbitrary objects; wrapping keys in custom domain types and forgetting to call toString() or serialize; library users passing protocol objects that are neither byte[] nor Rawable.

Related errors


AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08). Data as JSON: /api/errors/4a23c96ab14f70b4. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/redis/clients/jedis/ClusterCommandObjects.java:357

    return result;
  }

  /**
   * Calculates the hash slot for a preprocessed key.
   *
   * @param preprocessedKey the key after preprocessing (may be String, byte[], or Rawable)
   * @return the hash slot for the key
   */
  private int calculateSlotFromPreprocessedKey(Object preprocessedKey) {
    if (preprocessedKey instanceof byte[]) {
      return JedisClusterCRC16.getSlot((byte[]) preprocessedKey);
    } else if (preprocessedKey instanceof String) {
      return JedisClusterCRC16.getSlot((String) preprocessedKey);
    } else if (preprocessedKey instanceof redis.clients.jedis.args.Rawable) {
      return JedisClusterCRC16.getSlot(((redis.clients.jedis.args.Rawable) preprocessedKey).getRaw());
    }
    throw new IllegalArgumentException("Unsupported key type: " + preprocessedKey.getClass().getName());
  }

  /**
   * Helper method to create a CommandArguments for a group of keys/values.
   */
  private <T> CommandArguments createCommandArgsForGroup(
      CommandArguments args,
      List<T> groupedElements,
      IParams params,
      BiConsumer<CommandArguments, T> keyAdder,
      BiConsumer<CommandArguments, T> valueAdder,
      boolean insertKeyCount,
      int step) {

    boolean keyValueMode = valueAdder != null;
    CommandArguments slotArgs = commandArguments(args.getCommand());

    // Insert key count after command but before keys (e.g., numkeys for MSETEX)

View on GitHub (pinned to 6dac31d4c2)