Distributed systems
Redis CROSSSLOT — your operation spans more than one hash slot
Written and reviewed by Sahil Srivastav
CROSSSLOT Keys in request don't hash to the same slotWhat this error actually means
Redis Cluster partitions keys into hash slots. A multi-key command or atomic operation that requires keys in one slot is rejected when those keys map to different slots. This can fail even when the current cluster happens to place both slots on the same physical node: slot identity, not accidental node placement, defines the operation’s supported boundary.
Hash tags let related keys use a shared part of their name for slot calculation. For example, cart:{42}:items and cart:{42}:totals share the nonempty tag 42. This is useful only when the keys belong to one deliberate unit of work. Giving every key the same tag removes useful distribution and concentrates load on one slot.
A standalone development server does not expose this boundary. Code that used MGET, a transaction or a Lua script across arbitrary keys can therefore work locally and fail immediately after moving to Cluster. The error should trigger a data-model review, not a retry loop against another random node.
Causes, most common first
- 1Related keys were named without a shared slot boundary. A cart, session or aggregate is spread across names that hash independently. The application assumes a local transaction across those names, but the key design never encoded that requirement.
- 2A bulk command combines unrelated aggregates. A request may fetch keys for many users in one MGET. The operation is convenient on a single node but does not fit the native cluster command’s slot constraints. Decide whether independent reads are sufficient or a consistent aggregate is required.
- 3Hash-tag syntax or client key transformation differs. Empty braces, unexpected prefixes or nested naming conventions can cause the actual transmitted key to hash differently from the string a developer inspected. Compare final key bytes after the client applies its namespace rules.
- 4A script or transaction grows beyond its original aggregate. A later change adds a global counter or cross-account key to an otherwise local operation. The original tag still works for the old keys, but the expanded business invariant now spans slots.
When you see it
- Single-key operations work but MGET or a multi-key script fails
- An application passes standalone Redis tests and fails in Cluster
- Two keys are on the same node but the multi-key command still returns CROSSSLOT
- A client prefix or namespace change unexpectedly breaks transactions
How to diagnose it
Step 1
Calculate slots for the exact failing keys
These commands require a cluster-enabled server and do not create data. Run them with the actual connection options. Different numeric results prove the mismatch; do not infer slot equality from similar-looking key names.
redis-cli CLUSTER KEYSLOT cart:42:items
redis-cli CLUSTER KEYSLOT cart:42:totalsStep 2
Verify the proposed tag before changing writes
The quoted braces are literal key content. These two names should return the same slot. Use the smallest aggregate that truly needs atomic operations, rather than one shared tag for the whole application.
redis-cli CLUSTER KEYSLOT 'cart:{42}:items'
redis-cli CLUSTER KEYSLOT 'cart:{42}:totals'Step 3
Inspect the command after client transformation
Log command names and appropriately redacted key identities at the application boundary. Check every key passed to the failing script or transaction. Do not turn on a high-volume global command trace merely to inspect two known key names.
Step 4
Write down the required consistency guarantee
Determine whether the result must be one atomic snapshot or can be assembled from independent reads. This decides whether splitting by slot is a correct fix. A client successfully returning values is insufficient if the values no longer obey the original invariant.
The fix
For one aggregate that requires atomic updates, design all participating keys with a shared hash tag. Keep the aggregate bounded so a large customer does not monopolise one slot. Where appropriate, storing related fields in a single Redis value or hash can make the atomicity boundary more explicit.
For independent bulk reads, use a cluster-aware client capability that groups work by slot or issue separate commands. Preserve result ordering and per-key failures in the application. Do not describe the combined result as an atomic snapshot, because requests can observe different moments.
If the invariant genuinely spans unrelated aggregates, a hash-tag trick is usually not the whole design. Reconsider ownership, move the transaction to a system with the required transactional boundary, or model a multi-step workflow with explicit partial-failure handling. Silently replacing a transaction with sequential writes trades a visible error for inconsistent state.
Changing key names is a data migration. Plan readers, writers, expiration and old-key retirement together. Invalidate or migrate derived caches deliberately; do not dual-write durable state and assume the two name schemes remain consistent through failures.
How to stop it coming back
- Run integration checks against Cluster for every multi-key command, transaction and script used by the application.
- Document the hash-tag contract alongside each aggregate and enforce it in one key-construction function.
- Measure per-slot load and large-tenant skew after any grouping change; slot compatibility does not guarantee even distribution.
FAQ
Does redis-cli -c fix CROSSSLOT?
No. It follows routing redirects, but it cannot make keys in different slots satisfy a same-slot operation. Change the key grouping or operation semantics rather than repeatedly redirecting the same invalid command.
Can I tag every key with {app}?
That forces the tagged keys into one slot and defeats distribution for that workload. Use a bounded business aggregate as the tag only when its keys need to share an atomic operation.
Is a pipeline a cross-slot transaction?
No. A cluster client may distribute a pipeline to several nodes, but pipelining is a transport optimisation. It does not provide cross-slot atomicity or rollback if one part fails.
Related
Other errors engineers hit next to this one
- Redis OOM command not allowed above maxmemory
- MISCONF Redis is configured to save RDB snapshots
- READONLY You can’t write against a read only replica
- LOADING Redis is loading the dataset in memory
- MOVED and ASK replies from Redis Cluster
- Redis clients stall during KEYS on a large keyspace
- A Redis lock lease expires while the worker still runs
- HikariPool-1 - Connection is not available, request timed out