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 as CrossSlotTransactionError in TransactionStrategy.execute_command (redis/cluster.py:4684) during WATCH or immediate execution when the new command's slot differs from the slot(s) already pinned in _pipeline_slots. Redis Cluster transactions must operate on a single hash slot, so mixing slots is rejected.
Solutions
- Design keys to share a hash tag so they map to one slot: 'user:{tx1}', 'order:{tx1}'.
- Split the transaction into per-slot transactions if keys cannot share a tag.
- Use the non-transactional pipeline if cross-key atomicity is not actually required.
Example fix
// before
with rc.pipeline(transaction=True) as pipe:
pipe.watch('user:1')
pipe.watch('order:2')
// after
with rc.pipeline(transaction=True) as pipe:
pipe.watch('user:{tx1}')
pipe.watch('order:{tx1}') Defensive patterns
Strategy: validation
Validate before calling
from redis.cluster import key_slot
def same_slot(keys):
slots = {key_slot(k.encode()) for k in keys}
return len(slots) == 1
keys = ['user:{tx1}', 'order:{tx1}']
assert same_slot(keys) Type guard
from redis.cluster import key_slot
def keys_share_slot(keys) -> bool:
return len({key_slot(k.encode() if isinstance(k,str) else k) for k in keys}) == 1 Try / catch
from redis.exceptions import RedisClusterException
try:
pipe.execute()
except RedisClusterException as e:
if 'different slots' in str(e):
# redesign keys with a shared hash tag and retry Prevention
- Use shared hash tags ({tag}) for transactional key groups.
- Validate slot equality before queuing commands.
When it happens
Trigger: In a transactional pipeline, watching or executing commands on keys that hash to different slots, e.g. pipe.watch('user:1') then pipe.watch('order:2') where the keys lack a shared hash tag.
Common situations: Optimistic-locking patterns ported from standalone Redis that watch unrelated keys; multi-key transactions without hash-tag design.
Related errors
- All keys involved in a cluster transaction must map to the…
- At least a command with a key is needed to identify a node
- Cannot identify slot number for command
- Cannot issue a WATCH after a MULTI
- Cannot watch or send commands on different slots
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/84275e5ee37583e7.
Report an issue: GitHub.
Appendix: source
Thrown at redis/cluster.py:4684
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._resolve_transaction_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 6a6b581b48)