{"record":{"id":"84275e5ee37583e7","repo":"redis/redis-py","slug":"cannot-watch-or-send-commands-on-different-slots-84275e","errorCode":null,"errorMessage":"Cannot watch or send commands on different slots","messagePattern":"Cannot watch or send commands on different slots","errorType":"exception","errorClass":"CrossSlotTransactionError","httpStatus":null,"severity":"error","filePath":"redis/cluster.py","lineNumber":4684,"sourceCode":"        if not self._transaction_connection:\n            self._transaction_connection = get_connection(redis_node)\n\n        return redis_node, self._transaction_connection\n\n    def execute_command(self, *args, **kwargs):\n        slot_number: Optional[int] = None\n        if args[0] not in ClusterPipeline.NO_SLOTS_COMMANDS:\n            slot_number = self._resolve_transaction_slot(*args)\n\n        if (\n            self._watching or args[0] in self.IMMEDIATE_EXECUTE_COMMANDS\n        ) and not self._explicit_transaction:\n            if args[0] == \"WATCH\":\n                self._validate_watch()\n\n            if slot_number is not None:\n                if self._pipeline_slots and slot_number not in self._pipeline_slots:\n                    raise CrossSlotTransactionError(\n                        \"Cannot watch or send commands on different slots\"\n                    )\n\n                self._pipeline_slots.add(slot_number)\n            elif args[0] not in self.NO_SLOTS_COMMANDS:\n                raise RedisClusterException(\n                    f\"Cannot identify slot number for command: {args[0]},\"\n                    \"it cannot be triggered in a transaction\"\n                )\n\n            return self._immediate_execute_command(*args, **kwargs)\n        else:\n            if slot_number is not None:\n                self._pipeline_slots.add(slot_number)\n\n            return self.pipeline_execute_command(*args, **kwargs)\n\n    def _validate_watch(self):","sourceCodeStart":4666,"sourceCodeEnd":4702,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/cluster.py#L4666-L4702","documentation":"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.","triggerScenarios":"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.","commonSituations":"Optimistic-locking patterns ported from standalone Redis that watch unrelated keys; multi-key transactions without hash-tag design.","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."],"exampleFix":"// before\nwith rc.pipeline(transaction=True) as pipe:\n    pipe.watch('user:1')\n    pipe.watch('order:2')\n// after\nwith rc.pipeline(transaction=True) as pipe:\n    pipe.watch('user:{tx1}')\n    pipe.watch('order:{tx1}')","handlingStrategy":"validation","validationCode":"from redis.cluster import key_slot\ndef same_slot(keys):\n    slots = {key_slot(k.encode()) for k in keys}\n    return len(slots) == 1\nkeys = ['user:{tx1}', 'order:{tx1}']\nassert same_slot(keys)","typeGuard":"from redis.cluster import key_slot\ndef keys_share_slot(keys) -> bool:\n    return len({key_slot(k.encode() if isinstance(k,str) else k) for k in keys}) == 1","tryCatchPattern":"from redis.exceptions import RedisClusterException\ntry:\n    pipe.execute()\nexcept RedisClusterException as e:\n    if 'different slots' in str(e):\n        # redesign keys with a shared hash tag and retry","preventionTips":["Use shared hash tags ({tag}) for transactional key groups.","Validate slot equality before queuing commands."],"tags":["cluster","pipeline","transaction","cross-slot","optimistic-locking"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}