redis/redis-py · error · CrossSlotTransactionError
Cannot watch or send commands on different slots
Error message
Cannot watch or send commands on different slots
What it means
Raised in TransactionStrategy.execute_command (redis/cluster.py:4630) as CrossSlotTransactionError when a watched/immediate command in a transaction hashes to a slot different from those already in self._pipeline_slots. Redis Cluster transactions are atomic only within a single hash slot, so mixing slots during WATCH or immediate execution is rejected.
Source
Thrown at redis/cluster.py:4631
if not self._transaction_connection:
self._transaction_connection = get_connection(redis_node)
return redis_node, self._transaction_connection
def execute_command(self, *args, **kwargs):
slot_number: Optional[int] = None
if args[0] not in ClusterPipeline.NO_SLOTS_COMMANDS:
slot_number = self._pipe.determine_slot(*args)
if (
self._watching or args[0] in self.IMMEDIATE_EXECUTE_COMMANDS
) and not self._explicit_transaction:
if args[0] == "WATCH":
self._validate_watch()
if slot_number is not None:
if self._pipeline_slots and slot_number not in self._pipeline_slots:
raise CrossSlotTransactionError(
"Cannot watch or send commands on different slots"
)
self._pipeline_slots.add(slot_number)
elif args[0] not in self.NO_SLOTS_COMMANDS:
raise RedisClusterException(
f"Cannot identify slot number for command: {args[0]},"
"it cannot be triggered in a transaction"
)
return self._immediate_execute_command(*args, **kwargs)
else:
if slot_number is not None:
self._pipeline_slots.add(slot_number)
return self.pipeline_execute_command(*args, **kwargs)
def _validate_watch(self):View on GitHub (pinned to da03cdc7e8)
Solutions
- Put all keys of one transaction under a shared hash tag so they land in the same slot, e.g. 'user:{1}', 'order:{1}'.
- Split the operation into multiple single-slot transactions.
- Use a Lua script (via rc.eval) keyed on one slot to do multi-key logic atomically, again with a shared hash tag.
- Re-check your keys' slots with rc.cluster_keyslot(key) before issuing WATCH.
Example fix
# before
pipe = rc.pipeline(transaction=True)
pipe.watch('user:1')
pipe.multi()
pipe.set('order:1', 'x') # different slot -> CrossSlotTransactionError
pipe.execute()
# after (shared hash tag forces one slot)
pipe = rc.pipeline(transaction=True)
pipe.watch('{acct}:user')
pipe.multi()
pipe.set('{acct}:order', 'x')
pipe.execute() Defensive patterns
Strategy: validation
Validate before calling
from redis.cluster import RedisCluster
def assert_same_slot(client, keys):
slots = {client.cluster_keyslot(k) for k in keys}
if len(slots) != 1:
raise ValueError(f'keys span multiple slots: {slots}; use a shared hash tag')
def watch_and_mutate(client, watch_key, ops):
assert_same_slot(client, [watch_key] + [a[0] for a in ops])
pipe = client.pipeline(transaction=True)
pipe.watch(watch_key)
pipe.multi()
for args in ops:
pipe.execute_command(*args)
return pipe.execute() Try / catch
from redis.exceptions import RedisClusterException
try:
pipe.execute()
except RedisClusterException as e:
if 'different slots' in str(e):
# re-issue keys under a shared hash tag, e.g. '{tag}:k'
...
else:
raise Prevention
- Design keys with a shared hash tag ({tag}prefix) so multi-key transactions land on one slot.
- Pre-flight with rc.cluster_keyslot(k) for every key in the transaction.
- Split cross-entity operations into separate single-slot transactions.
When it happens
Trigger: pipe.watch('user:1'); pipe.get('order:9') where the two keys hash to different slots. Or any immediate-execute command (WATCH/UNWATCH or a command issued while _watching is True and no MULTI yet) whose slot is not the one already recorded.
Common situations: Keys naively named without a shared hash tag. Porting multi-key WATCH/transaction logic from standalone redis to cluster. Using natural keys that span logical entities (user vs order) in one transaction.
Related errors
- Cannot watch or send commands on different slots
- All keys involved in a cluster transaction must map to the s
- Cannot identify slot number for command: {args[0]},it cannot
- At least a command with a key is needed to identify a node
- Cannot identify slot number for command: {args[0]},it cannot
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/84275e5ee37583e7.json.
Report an issue: GitHub.