Redis "CROSSSLOT Keys in request don't hash to the same slot" is the error you get when one command, transaction or script touches keys that live in different hash slots of a Redis Cluster. On a single instance the same code works. In a cluster, keys are spread across nodes, and Redis refuses multi-key operations it cannot run on one node atomically. Valkey Cluster returns exactly the same message.
Why the error exists
The Redis Cluster specification splits the key space into 16384 hash slots, with HASH_SLOT = CRC16(key) mod 16384. Each primary owns a subset of slots. A command such as MGET a b is only safe if both keys are on the same node, and Redis checks this at the slot level: all keys in the request must map to one slot, not merely to one node. When they do not, the node replies with CROSSSLOT instead of executing anything.
127.0.0.1:7000> MGET user:1000:name user:1001:name
(error) CROSSSLOT Keys in request don't hash to the same slot
127.0.0.1:7000> CLUSTER KEYSLOT user:1000:name
(integer) ...
127.0.0.1:7000> CLUSTER KEYSLOT user:1001:name
(integer) ... # a different slot
Where it shows up
- Multi-key commands:
MGET,MSET,DELorUNLINKwith several keys,SUNIONSTORE,SINTER,RENAME,ZUNIONSTOREand similar. - Transactions. In cluster mode Redis checks all queued commands when
EXECarrives. In the source, a transaction whose commands touch different slots gets CROSSSLOT and is discarded, so nothing in it runs. - Lua scripts and functions. The docs require every key a script touches to be passed as a key argument, and declared keys must always hash to one slot. Functions and scripts with a shebang header also cannot touch undeclared keys from other slots by default; they fail with "Script attempted to access keys that do not hash to the same slot". Old-style
EVALscripts without a shebang are more lenient, but a key served by another node still fails. - Client pipelines. Pipelines are not atomic and good cluster clients route each command to its own node, so pipelines usually do not hit CROSSSLOT. Transactions and multi-key commands inside them still do.
The fix: hash tags
A hash tag tells Redis to hash only part of the key. The spec gives the exact rules: if the key contains {, there is a } to its right, and at least one character between the first { and the first } after it, then only that substring is hashed.
{user:1000}.name -> hashes "user:1000"
{user:1000}.cart -> hashes "user:1000" (same slot)
foo{}{bar} -> hashes the whole key (empty first tag)
foo{{bar}}zap -> hashes "{bar"
foo{bar}{zap} -> hashes "bar" (only the first tag counts)
So the typical fix is to put the entity ID in braces for keys that must be used together:
# before: keys land in random slots
MSET user:1000:name Anna user:1000:email anna@example.com
# after: one hash tag, one slot, MSET works in cluster
MSET {user:1000}:name Anna {user:1000}:email anna@example.com
# check before you deploy
CLUSTER KEYSLOT {user:1000}:name
CLUSTER KEYSLOT {user:1000}:email
CLUSTER KEYSLOT shows the slot for any key name. Put it into a test, so a renamed key does not quietly break a transaction later.
Other ways out
- Split the request by slot. If you do not need atomicity, run one command per slot. Some clients do this for you; for example, redis-py's cluster client has
mget_nonatomicandmset_nonatomic, which group keys by slot and send oneMGETorMSETper slot. The name is honest: the result is no longer atomic. - Rethink the data model. Several keys that always change together are often better as one hash. A user profile in
HSET {user:1000} name ... email ...needs no cross-key atomicity at all. - Script flag
allow-cross-slot-keys. Redis 7+ scripts and functions can declare this flag to access undeclared keys from several slots. The docs say declared keys must still hash to one slot, and call cross-slot access discouraged; in the source, a key served by another node still fails. Treat it as a migration aid, not a design.
{app}: on every key sends the whole dataset into a single slot, so a single node holds all of it and takes all the traffic. The cluster still runs, but you are back to one server, with extra moving parts.Hash tags on large datasets
- A slot cannot be split. All keys with the same tag live in one slot, and a slot always belongs to one primary. If one tenant or one tag grows to tens of GB, that node runs out of memory first, and adding nodes does not help. Choose a tag that keeps each group small, such as a user or order ID, not a tenant or a country.
- Hot slots mean hot nodes. Even with even memory, a popular tag concentrates CPU and network on one node. Watch per-node ops and memory, and compare nodes with
redis-cli --cluster infoandCLUSTER COUNTKEYSINSLOT. - Resharding moves whole slots. Migrating a slot with millions of keys or very large keys takes time and puts load on both nodes. According to the spec, during migration multi-key operations on keys that are split between source and target, or that do not exist, get
-TRYAGAIN. Clients need a retry path for that, and large slots stay in this state longer. - Plan the migration from standalone Redis. Before moving a big instance into a cluster (or from Redis to Valkey Cluster, see our Redis to Valkey migration guide), find all multi-key commands, transactions and scripts in the code. Then decide on tags and rename keys. Renaming keys later in a live multi-GB cluster is much harder than doing it during the migration.
- Test with production-like key counts. Uneven slots and long migrations only show up with real key distribution and real key sizes.
If the cluster itself stops serving slots, that is a different problem: see our guide to Redis CLUSTERDOWN.
Key takeaways
- CROSSSLOT means one command, transaction or script touched keys in different hash slots; Redis and Valkey Cluster refuse it.
- Fix it with hash tags: only the text inside the first non-empty
{...}is hashed; check withCLUSTER KEYSLOT. - If you do not need atomicity, split requests by slot; consider hashes instead of many related keys.
- Never use one constant tag for all keys; tag by a small entity such as a user or order ID.
- On large datasets watch for oversized or hot slots, and expect TRYAGAIN for multi-key commands during resharding.