{"record":{"id":"9cefd59b7f148014","repo":"redis/redis-py","slug":"all-keys-involved-in-a-cluster-transaction-must-ma","errorCode":null,"errorMessage":"All keys involved in a cluster transaction must map to the same slot","messagePattern":"All keys involved in a cluster transaction must map to the same slot","errorType":"exception","errorClass":"CrossSlotTransactionError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/cluster.py","lineNumber":3378,"sourceCode":"\n        return await self._execute_transaction_with_retries(stack, raise_on_error)\n\n    async def _execute_transaction_with_retries(\n        self, stack: List[\"PipelineCommand\"], raise_on_error: bool\n    ):\n        return await self._retry.call_with_retry(\n            lambda: self._execute_transaction(stack, raise_on_error),\n            lambda error, failure_count: self._reinitialize_on_error(\n                error, failure_count\n            ),\n            with_failure_count=True,\n        )\n\n    async def _execute_transaction(\n        self, stack: List[\"PipelineCommand\"], raise_on_error: bool\n    ):\n        if len(self._pipeline_slots) > 1:\n            raise CrossSlotTransactionError(\n                \"All keys involved in a cluster transaction must map to the same slot\"\n            )\n\n        self._executing = True\n\n        redis_node, connection = self._get_client_and_connection_for_transaction()\n        # Only disconnect if not watching - disconnecting would lose WATCH state\n        if not self._watching:\n            await redis_node.disconnect_if_needed(connection)\n\n        # Ensure fieldsets referenced by buffered HIMPORT SETs are prepared on this\n        # node's connection before the MULTI/EXEC block (session state, not\n        # transactional). All keys share one slot here, so it is a single node.\n        await redis_node._himport_prepare_pipeline(connection, stack)\n\n        stack = chain(\n            [PipelineCommand(0, \"MULTI\")],\n            stack,","sourceCodeStart":3360,"sourceCodeEnd":3396,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/cluster.py#L3360-L3396","documentation":"CrossSlotTransactionError raised at the top of TransactionStrategy._execute_transaction (redis/asyncio/cluster.py:3377) when the accumulated pipeline slots contain more than one distinct slot. Redis Cluster guarantees atomicity only within a single slot, so a MULTI/EXEC block spanning multiple slots is impossible. This fires at execute() time after all commands were queued.","triggerScenarios":"Queueing `pipe.set('k1', '1'); pipe.set('k2', '2'); await pipe.execute()` inside a transaction where k1 and k2 map to different slots.","commonSituations":"Porting a standalone-Redis transactional pipeline to cluster without hash tags; aggregating unrelated keys in one transaction.","solutions":["Group keys by hash slot using hash tags, e.g. 'k{group1}', so all keys share a slot","Split into several single-slot transactions","If atomicity is not required, use the non-atomic cluster pipeline strategy"],"exampleFix":"// before\npipe.multi()\npipe.set('user:1', 'a')\npipe.set('account:2', 'b')\nawait pipe.execute()\n// after - same slot via shared hash tag\npipe.multi()\npipe.set('user:{group1}', 'a')\npipe.set('account:{group1}', 'b')\nawait pipe.execute()","handlingStrategy":"validation","validationCode":"from redis.cluster import key_slot\nslots = {key_slot(k.encode()) for k in keys}\nif len(slots) > 1:\n    raise ValueError('transaction keys span multiple slots; use hash tags or split')","typeGuard":null,"tryCatchPattern":"try:\n    await pipe.execute()\nexcept CrossSlotTransactionError:\n    # rebucket with hash tags or split into per-slot transactions","preventionTips":["Use hash tags to colocate transaction keys","Validate slots before calling execute()"],"tags":["cluster","pipeline","transaction","multi","cross-slot"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}