redis/redis-py · error · CrossSlotTransactionError
All keys involved in a cluster transaction must map to the s
Error message
All keys involved in a cluster transaction must map to the same slot
What it means
Raised as CrossSlotTransactionError at the top of _execute_transaction when len(self._pipeline_slots) > 1. The buffered (deferred) branch of _execute_command collects every queued command's slot; at execute time, if more than one distinct slot is present, the library cannot wrap them in a single MULTI/EXEC (which is single-node in Redis Cluster).
Source
Thrown at redis/asyncio/cluster.py:3346
return await self._execute_transaction_with_retries(stack, raise_on_error)
async def _execute_transaction_with_retries(
self, stack: List["PipelineCommand"], raise_on_error: bool
):
return await self._retry.call_with_retry(
lambda: self._execute_transaction(stack, raise_on_error),
lambda error, failure_count: self._reinitialize_on_error(
error, failure_count
),
with_failure_count=True,
)
async def _execute_transaction(
self, stack: List["PipelineCommand"], raise_on_error: bool
):
if len(self._pipeline_slots) > 1:
raise CrossSlotTransactionError(
"All keys involved in a cluster transaction must map to the same slot"
)
self._executing = True
redis_node, connection = self._get_client_and_connection_for_transaction()
# Only disconnect if not watching - disconnecting would lose WATCH state
if not self._watching:
await redis_node.disconnect_if_needed(connection)
# Ensure fieldsets referenced by buffered HIMPORT SETs are prepared on this
# node's connection before the MULTI/EXEC block (session state, not
# transactional). All keys share one slot here, so it is a single node.
await redis_node._himport_prepare_pipeline(connection, stack)
stack = chain(
[PipelineCommand(0, "MULTI")],
stack,View on GitHub (pinned to da03cdc7e8)
Solutions
- Add a shared hash tag to all keys in the transaction so they map to one slot (e.g. 'user:{42}', 'acct:{42}').
- Split the work into multiple single-slot transactions, one per slot.
- If atomicity is not required, use the non-transactional cluster pipeline (client.pipeline(transaction=False)) which fans out across slots.
Example fix
// before
pipe = client.pipeline(transaction=True)
await pipe.set('user:1', 'a')
await pipe.set('user:2', 'b') # different slot
await pipe.execute() # raises [86]
// after
pipe = client.pipeline(transaction=True)
await pipe.set('user:{1}', 'a')
await pipe.set('acct:{1}', 'b') # same slot via tag
await pipe.execute() Defensive patterns
Strategy: validation
Validate before calling
from redis.cluster import key_slot
from collections import defaultdict
buckets = defaultdict(list)
for k, v in mapping.items():
buckets[key_slot(k.encode())].append((k, v))
# then one transaction per slot, or use hash tags to collapse to one Try / catch
from redis.exceptions import CrossSlotTransactionError
try:
await pipe.execute()
except CrossSlotTransactionError:
# split commands by slot and execute one transaction per slot Prevention
- Add a shared hash tag to keys that must be transacted together.
- Validate single-slot before calling execute() on a transactional pipeline.
When it happens
Trigger: Queueing several deferred commands (the default pipeline path before execute()) whose keys hash to different slots, then calling execute() with transaction=True on a cluster pipeline. Example: pipe.set('a',1); pipe.set('b',2); await pipe.execute() with 'a' and 'b' in different slots.
Common situations: Treating a cluster pipeline like a standalone pipeline and batching unrelated keys; forgetting hash tags for keys that must be transacted together.
Related errors
- Cannot watch or send commands on different slots
- Cannot watch or send commands on different slots
- At least a command with a key is needed to identify a node
- Cannot identify slot number for command: {args[0]},it cannot
- Cannot issue a WATCH after a MULTI
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/9cefd59b7f148014.json.
Report an issue: GitHub.