Distributed systems

Redis CROSSSLOT — your operation spans more than one hash slot

Written and reviewed by Sahil Srivastav

Redis ClusterHash slotsAtomicity boundary
CROSSSLOT Keys in request don't hash to the same slot

What 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

  1. 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.
  2. 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.
  3. 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.
  4. 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:totals

Step 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.

Practise production debugging in a real repository

Reading about a failure and reproducing one are different skills. Gronex ships broken backend repositories with failing test suites that encode the real invariant, so you debug from evidence instead of memorising symptoms.

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

Full error and symptom index →