redis/jedis · error · JedisClusterOperationException

Cannot get connection for command with multiple hash slots

Error message

Cannot get connection for command with multiple hash slots

What it means

ClusterConnectionProvider.getConnection() computes the hash slots of all keys in the command; Redis cluster commands must touch exactly one slot, so if the CommandArguments contain keys hashing to more than one slot it throws JedisClusterOperationException instead of sending an invalid cross-slot command.

Solutions

  1. Split the operation into per-slot commands (group keys by hash slot) and issue one command per slot.
  2. Use hash tags ({user1000}.field) so related keys colocate in the same slot.
  3. Use a pipeline on the cluster client (which routes per-slot automatically) instead of a single multi-key command.

Example fix

// before
jedis.mget("user:1", "order:2"); // different slots
// after
jedis.mget("{user:1}:a", "{user:1}:b"); // same slot via hash tag
Defensive patterns

Strategy: validation

Validate before calling

Set<Integer> slots = new HashSet<>();
for (String key : keys) slots.add(JedisClusterCRC16.getSlot(SafeEncoder.encode(key)));
if (slots.size() > 1) throw new IllegalArgumentException("Keys span multiple cluster slots: " + slots);

Type guard

boolean singleSlot(List<String> keys) { return keys.stream().map(k -> JedisClusterCRC16.getSlot(k.getBytes(StandardCharsets.UTF_8))).distinct().count() <= 1; }

Try / catch

try {
  return jedis.mget(keys.toArray(new String[0]));
} catch (JedisClusterOperationException e) {
  return keys.stream().collect(partitioningBySlot()).values().stream()
      .map(group -> jedis.mget(group.toArray(new String[0])))
      .flatMap(List::stream).collect(toList());
}

Prevention

When it happens

Trigger: Issuing a multi-key command (e.g. MGET, MSET, SUNION, DEL of several keys, pipelines with multiple keys per command) whose keys hash to different slots on a cluster connection.

Common situations: Multi-key operations after re-sharding moved keys into different slots; pipelines reused between standalone and cluster modes; batch code that assumes all keys share a keytag/prefix.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/main/java/redis/clients/jedis/providers/ClusterConnectionProvider.java:131

  public Map<String, ConnectionPool> getPrimaryNodes() {
    return cache.getPrimaryNodes();
  }

  public HostAndPort getNode(int slot) {
    return slot >= 0 ? cache.getSlotNode(slot) : null;
  }

  public Connection getConnection(HostAndPort node) {
    return node != null ? cache.setupNodeIfNotExist(node).getResource() : getConnection();
  }

  @Override
  public Connection getConnection(CommandArguments args) {
    Set<Integer> slots = args.getKeyHashSlots();

    if (slots.size() > 1) {
      throw new JedisClusterOperationException("Cannot get connection for command with multiple hash slots");
    }

    int slot = slots.iterator().next();
    return slot >= 0 ? getConnectionFromSlot(slot) : getConnection();
  }

  public Connection getReplicaConnection(CommandArguments args) {
    Set<Integer> slots = args.getKeyHashSlots();

    if (slots.size() > 1) {
      throw new JedisClusterOperationException("Cannot get connection for command with multiple hash slots");
    }

    int slot = slots.iterator().next();
    return slot >= 0 ? getReplicaConnectionFromSlot(slot) : getConnection();
  }

  @Override

View on GitHub (pinned to 6dac31d4c2)