{"record":{"id":"38bdd069a0735e8e","repo":"redis/redis-py","slug":"cannot-watch-or-send-commands-on-different-slots","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/asyncio/cluster.py","lineNumber":3184,"sourceCode":"    async def _execute_command(\n        self, *args: Union[KeyT, EncodableT], **kwargs: Any\n    ) -> Any:\n        if self._pipe.cluster_client._initialize:\n            await self._pipe.cluster_client.initialize()\n\n        slot_number: Optional[int] = None\n        if args[0] not in self.NO_SLOTS_COMMANDS:\n            slot_number = await 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 super().execute_command(*args, **kwargs)\n\n    def _validate_watch(self):","sourceCodeStart":3166,"sourceCodeEnd":3202,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/cluster.py#L3166-L3202","documentation":"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.","triggerScenarios":"`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.","commonSituations":"Forgetting to use hash tags ({tag}) when transacting over logically related keys; assuming cluster transactions behave like standalone transactions.","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"],"exampleFix":"// before\nawait pipe.watch('user:1')\nawait pipe.watch('account:2')\n// after - same slot via hash tag\nawait pipe.watch('user:{1}')\nawait pipe.watch('account:{1}')","handlingStrategy":"validation","validationCode":"from redis.cluster import key_slot\nslots = {key_slot(k.encode()) for k in watch_keys}\nif len(slots) > 1:\n    raise ValueError('watch keys map to different slots; use hash tags')","typeGuard":null,"tryCatchPattern":"try:\n    await pipe.watch(*keys)\nexcept CrossSlotTransactionError:\n    # rebucket keys with hash tags or split transactions","preventionTips":["Use hash tags to colocate transaction keys in one slot","Validate slots up front when building cluster transactions"],"tags":["cluster","pipeline","transaction","watch","cross-slot"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}