redis/jedis · error · JedisClusterOperationException
Cannot get NodeKey for command with multiple hash slots
Error message
Cannot get NodeKey for command with multiple hash slots
What it means
ClusterPipeline.getNodeKey determines which cluster node a pipelined command should be sent to by looking at the command's hash slots. Multi-key commands whose keys map to more than one hash slot cannot be assigned to a single node, so JedisClusterOperationException is thrown. Such commands must be executed with hash tags or via cross-slot-safe APIs.
Solutions
- Wrap related keys in the same hash tag so they share a slot, e.g. {user42}.profile and {user42}.settings.
- Split the multi-key command into per-key commands so each pipelined command targets a single slot.
- Execute the multi-key command outside the pipeline (cluster-level APIs may reshard/route differently), or group commands by slot before pipelining.
Example fix
// before
pipeline.mset("user:1:name", "a", "user:2:name", "b");
// after
pipeline.mset("{user:1}:name", "a", "{user:1}:email", "x"); // keys share slot Defensive patterns
Strategy: validation
Validate before calling
static void assertSameSlot(String... keys) {
Set<Integer> slots = Arrays.stream(keys)
.map(k -> JedisClusterCRC16.getSlot(JedisClusterHashTagUtil.getHashTag(k) != null ? k : k))
.collect(Collectors.toSet());
if (slots.size() > 1)
throw new IllegalStateException("Keys span multiple slots: use hash tags");
} Type guard
static boolean sameSlot(String a, String b) {
return JedisClusterCRC16.getSlot(a) == JedisClusterCRC16.getSlot(b);
} Try / catch
try {
pipeline.mset(pairs);
} catch (JedisClusterOperationException e) {
if (e.getMessage().contains("multiple hash slots")) {
// fall back to per-key commands or wrap keys in a hash tag
} else throw e;
} Prevention
- Design key names with hash tags ({userId}:field) for data accessed together.
- Batch multi-key operations per slot instead of globally.
- Verify multi-key commands with JedisClusterCRC16.getSlot() in unit tests.
When it happens
Trigger: Pipelining (ClusterPipeline/PipeliningBase) multi-key commands like MSET, DEL k1 k2, SUNION, or RENAME whose keys hash to different slots — i.e. keys without matching {hashtag} prefixes.
Common situations: Bulk-deleting or bulk-writing many unrelated keys in one pipeline call; renaming or moving data between keys created without hash tags; moving from standalone (where multi-key ops are free) to cluster mode.
Related errors
- Cluster mode only supports SCAN command with MATCH pattern…
- Not supported in cluster mode.
- Unsupported key type
- Cannot use Jedis when in Pipeline. Please use Pipeline or…
- Command '' with request policy cannot be executed in…
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/5d1891e1e6973aea.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/ClusterPipeline.java:144
return new ClusterCommandObjects(RedisProtocol.orServerDefault(effective));
};
}
@Override
public void close() {
try {
super.close();
} finally {
IOUtils.closeQuietly(closeable);
}
}
@Override
protected HostAndPort getNodeKey(CommandArguments args) {
Set<Integer> slots = args.getKeyHashSlots();
if (slots.size() > 1) {
throw new JedisClusterOperationException("Cannot get NodeKey for command with multiple hash slots");
}
if (slots.isEmpty()) {
return null; // Let getConnection(null) handle it by using a random node
}
return provider.getNode(slots.iterator().next());
}
@Override
protected Connection getConnection(HostAndPort nodeKey) {
return provider.getConnection(nodeKey);
}
public Response<Long> spublish(String channel, String message) {
return appendCommand(commandObjects.spublish(channel, message));
}
View on GitHub (pinned to 6dac31d4c2)