How to fix CROSSSLOT Keys in request don't hash to the same slot in Redis
Redis Cluster returns `CROSSSLOT Keys in request don't hash to the same slot` when you attempt a multi-key operation (like MGET, MSET, transactions, or SUNION) on keys that hash to different hash slots. Redis Cluster partitions data across 16384 slots, and multi-key commands require all keys to map to the same slot unless you use hash tags. This guide explains slot hashing, hash tags, and how to fix key design issues.
Quick fix
Fixes CROSSSLOT
# Connect to any Redis Cluster node
redis-cli -c -h <host> -p <port>
# Check slot for individual keys
CLUSTER KEYSLOT user:123:profile
CLUSTER KEYSLOT user:123:sessions
CLUSTER KEYSLOT session:456:data
# Example output:
# (integer) 650
# (integer) 8734
# (integer) 200- Verify the slot mapping of your keys
- Apply hash tags to force keys into the same slot
- Handle transactions with hash tags
- Split multi-key operations across slots
# Connect to any Redis Cluster noderedis-cli -c -h <host> -p <port># Check slot for individual keysCLUSTER KEYSLOT user:123:profileCLUSTER KEYSLOT user:123:sessionsCLUSTER KEYSLOT session:456:data# Example output:# (integer) 650# (integer) 8734# (integer) 200CROSSSLOT Keys in request don't hash to the same slot
What this error means
Redis Cluster divides the key space into 16384 hash slots, each assigned to a specific master node. When you issue a command that involves multiple keys—such as `MGET`, `MSET`, `MULTI/EXEC`, `SUNION`, or `DEL`—Redis must ensure all those keys belong to the same hash slot; otherwise, the operation cannot be performed atomically on a single node. The error "CROSSSLOT Keys in request don't hash to the same slot" appears when the client library or Redis itself detects that the keys involved in a multi‑key command hash to different slots. This is a fundamental limitation of Redis Cluster: operations cannot span multiple nodes in a single atomic transaction. To work around this limitation, you can either: 1. Use **hash tags** (curly braces `{}` inside the key name) to force keys to the same slot, 2. Restructure your data so that related keys naturally hash together, 3. Use client‑side routing to send each key to its correct node individually, or 4. Avoid multi‑key commands altogether in favor of single‑key operations.
Typical symptoms
- Redis client throws `CROSSSLOT` exception when calling `MGET`, `MSET`, `DEL` with multiple keys
- Multi-key operations work in standalone Redis but fail after migrating to Redis Cluster
- Transactions (`MULTI/EXEC`) fail with CROSSSLOT error when keys span different slots
- Set operations like `SUNION`, `SINTER`, `SDIFF` fail across different slots
- Keys that appear related (e.g., `user:123:profile`, `user:123:sessions`) produce different hash slot values
- Application logs show cross-slot errors during bulk operations or pipeline requests
Common causes
- Using multi-key Redis commands (MGET, MSET, SINTER, SUNION, etc.) on keys that hash to different slots in a Redis Cluster
- Attempting transactions (MULTI/EXEC) on keys distributed across multiple cluster nodes
- Keys not designed with hash tags, causing naturally different CRC16 hashes for related data
- Client library not implementing automatic routing or hash-tag awareness for cluster operations
- Migrating from standalone Redis to Redis Cluster without updating application code to respect slot boundaries
- Using pipelining with commands that span multiple keys in different slots
How to fix "CROSSSLOT Keys in request don't hash to the same slot"
Use redis-cli to check which slot each key belongs to:
# Connect to any Redis Cluster node
redis-cli -c -h <host> -p <port>
# Check slot for individual keys
CLUSTER KEYSLOT user:123:profile
CLUSTER KEYSLOT user:123:sessions
CLUSTER KEYSLOT session:456:data
# Example output:
# (integer) 650
# (integer) 8734
# (integer) 200If the slot numbers differ, those keys cannot be used together in a multi‑key command unless you employ hash tags.
Redis allows you to wrap a portion of the key in curly braces {}; only the text inside the braces is used for slot calculation:
# Without hash tags – different slots
CLUSTER KEYSLOT user:123:profile # slot 7592
CLUSTER KEYSLOT user:123:sessions # slot 10411
# With hash tags – same slot
CLUSTER KEYSLOT user:{123}:profile # slot 3300 (based on '123')
CLUSTER KEYSLOT user:{123}:sessions # slot 3300 (based on '123')Update your application to use hash tags for related keys:
// Instead of (will cause CROSSSLOT)
const keys = ['user:123:profile', 'user:123:sessions'];
redis.mget(...keys);
// Use hash tags (all hash to same slot)
const keys = ['user:{123}:profile', 'user:{123}:sessions'];
redis.mget(...keys); // Works!Now MGET, MSET, and other multi‑key commands will work because both keys hash to slot 3300.
When using MULTI/EXEC transactions, all keys accessed within the transaction must hash to the same slot:
// Without hash tags – fails with CROSSSLOT
redis.multi()
.get('user:123:name')
.get('session:456:token')
.exec();
// With hash tags – all keys in same slot
redis.multi()
.get('user:{123}:name')
.get('session:{123}:token')
.exec();Apply hash tags consistently across your transaction to ensure atomicity.
If hash tags are not feasible, break multi‑key commands into single‑key operations routed to the correct node:
// Instead of MGET that fails with CROSSSLOT
redis.mget('key1', 'key2', 'key3'); // Fails if keys in different slots
// Use individual GET calls
const values = await Promise.all([
redis.get('key1'),
redis.get('key2'),
redis.get('key3')
]);For deletions and set operations:
# Instead of DEL key1 key2 key3 (fails if in different slots)
DEL key1
DEL key2
DEL key3Most Redis Cluster clients (ioredis, redis-py-cluster, node-redis) handle this routing automatically when you use single‑key commands.
For better performance, batch keys by their hash slot before executing multi-key operations:
const redis = require('ioredis');
const cluster = new redis.Cluster([...nodes]);
// Get multiple values efficiently by grouping by slot
const keys = ['user:{1}:name', 'user:{1}:email', 'user:{2}:name', 'user:{2}:email'];
// Group by hash tag (all user:{1} keys go together)
const groupedBySlot = groupByHashTag(keys);
const results = {};
for (const [tag, keyGroup] of Object.entries(groupedBySlot)) {
const values = await cluster.mget(...keyGroup);
results[tag] = values;
}This approach reduces network round‑trips while respecting slot boundaries.
Modern Redis clients automatically handle slot routing. Verify your client's cluster support:
// ioredis example – automatically handles cluster routing
const Redis = require('ioredis');
const cluster = new Redis.Cluster([
{ host: '127.0.0.1', port: 7000 },
{ host: '127.0.0.1', port: 7001 },
]);
// Use hash tags for multi-key commands
await cluster.mget('user:{1}:name', 'user:{1}:email');# redis-py-cluster example
from rediscluster import RedisCluster
startup_nodes = [
{'host': '127.0.0.1', 'port': 7000},
{'host': '127.0.0.1', 'port': 7001},
]
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
# Use hash tags
rc.mget('user:{1}:name', 'user:{1}:email')These clients maintain a slot‑to‑node map and handle key routing transparently.
Advanced notes
Redis Cluster's slot‑hashing algorithm is CRC16 modulo 16384. The same algorithm is used consistently for all keys. Hash tags work by extracting the substring between the first { and the next } (or end of string if no closing brace) and hashing only that substring.
Performance considerations: Splitting a 100‑key MGET into 100 individual GET requests increases network round‑trips significantly. If you cannot use hash tags, consider batching keys by slot on the client side and issuing separate multi‑key commands per slot to balance consistency and performance.
Data skew warning: Aggressive hash tagging can cause uneven data distribution. For example, using {user}:profile, {user}:session, {user}:settings for all users puts all user data in one slot, potentially causing that slot to become a bottleneck. Use hash tags strategically based on your access patterns.
Migration strategy: When moving from standalone Redis to Redis Cluster, audit all multi‑key commands (MGET, MSET, SUNION, SINTER, RPOPLPUSH, BRPOPLPUSH, EVAL, etc.), transactions, and pipelined requests. Tools like redis‑cli --cluster check can help identify cross‑slot violations before going live.
Redis Enterprise workaround: Redis Enterprise has built-in support for some cross-slot commands (MGET, MSET, DEL, UNLINK, EXISTS, TOUCH), allowing them to work across slots without hash tags. Open-source Redis Cluster does not support this.
Frequently asked questions
- What does "CROSSSLOT" mean?
- Redis Cluster divides the key space into 16384 hash slots, each assigned to a specific master node. When you issue a command that involves multiple keys—such as MGET, MSET, MULTI/EXEC, SUNION, or DEL—Redis must ensure all those keys belong to the same hash slot; otherwise, the operation cannot be performed atomically on a single node. The error "CROSSSLOT Keys in request don't hash to the same slot" appears when the client library or Redis itself detects that the keys involved in a multi‑key command hash to different slots.
- How do I fix "CROSSSLOT"?
- Redis Cluster returns CROSSSLOT Keys in request don't hash to the same slot when you attempt a multi-key operation (like MGET, MSET, transactions, or SUNION) on keys that hash to different hash slots. Redis Cluster partitions data across 16384 slots, and multi-key commands require all keys to map to the same slot unless you use hash tags. This guide explains slot hashing, hash tags, and how to fix key design issues.
- What causes "CROSSSLOT"?
- Using multi-key Redis commands (MGET, MSET, SINTER, SUNION, etc.) on keys that hash to different slots in a Redis Cluster Attempting transactions (MULTI/EXEC) on keys distributed across multiple cluster nodes Keys not designed with hash tags, causing naturally different CRC16 hashes for related data
- Is the "CROSSSLOT" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.