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

  1. Wrap related keys in the same hash tag so they share a slot, e.g. {user42}.profile and {user42}.settings.
  2. Split the multi-key command into per-key commands so each pipelined command targets a single slot.
  3. 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

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


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)