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
CrossSlotTransactionError raised in TransactionStrategy._execute_command (redis/asyncio/cluster.py:3184) during the WATCH/immediate path. While watching, all commands must target the same slot as the already-registered pipeline slots; attempting to watch or run a command whose slot differs from the existing one breaks the single-node transaction guarantee. Redis Cluster transactions are only atomic within one hash slot.
Solutions
- Use hash tags to force keys into the same slot: 'user:{1}' and 'account:{1}'
- Split the work into separate single-slot transactions
- Switch to the non-atomic pipeline strategy if cross-slot operation is acceptable
Example fix
// before
await pipe.watch('user:1')
await pipe.watch('account:2')
// after - same slot via hash tag
await pipe.watch('user:{1}')
await pipe.watch('account:{1}') Defensive patterns
Strategy: validation
Validate before calling
from redis.cluster import key_slot
slots = {key_slot(k.encode()) for k in watch_keys}
if len(slots) > 1:
raise ValueError('watch keys map to different slots; use hash tags') Try / catch
try:
await pipe.watch(*keys)
except CrossSlotTransactionError:
# rebucket keys with hash tags or split transactions Prevention
- Use hash tags to colocate transaction keys in one slot
- Validate slots up front when building cluster transactions
When it happens
Trigger: `pipe.watch('user:1')` then `pipe.watch('user:2')` where the two keys hash to different slots; mixing a watched key with an immediate command on a different slot before MULTI.
Common situations: Forgetting to use hash tags ({tag}) when transacting over logically related keys; assuming cluster transactions behave like standalone transactions.
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 identify slot number for command
- Cannot issue a WATCH after a MULTI
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/38bdd069a0735e8e.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/cluster.py:3184
async def _execute_command(
self, *args: Union[KeyT, EncodableT], **kwargs: Any
) -> Any:
if self._pipe.cluster_client._initialize:
await self._pipe.cluster_client.initialize()
slot_number: Optional[int] = None
if args[0] not in self.NO_SLOTS_COMMANDS:
slot_number = await 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 super().execute_command(*args, **kwargs)
def _validate_watch(self):View on GitHub (pinned to 6a6b581b48)