redis/redis-py · error · RedisClusterException
method multi() is not supported outside of transactional…
Error message
method multi() is not supported outside of transactional context
What it means
Raised by AbstractStrategy.multi() in redis/cluster.py:4547. In Redis Cluster a MULTI/EXEC transaction must run on a single connection pinned to one slot, so multi() is only valid when invoked through the cluster transaction pipeline entry point. Calling multi() directly on a plain (non-transactional) cluster pipeline has no meaning and is rejected.
Solutions
- Open the pipeline as a transaction from the start: with rc.pipeline(transaction=True) as pipe: ...
- Remove the explicit .multi() call; the transactional pipeline handles MULTI implicitly on execute().
- Use the default non-transactional pipeline and drop the multi() call entirely if atomicity is not needed.
Example fix
// before
with rc.pipeline() as pipe:
pipe.multi()
pipe.set('k', 'v')
pipe.execute()
// after
with rc.pipeline(transaction=True) as pipe:
pipe.set('k', 'v')
pipe.execute() Defensive patterns
Strategy: validation
Validate before calling
with rc.pipeline(transaction=True) as pipe:
pipe.set('k', 'v')
pipe.execute() # MULTI handled implicitly; no .multi() call Type guard
def is_transactional_pipe(pipe) -> bool:
return getattr(pipe, '_transaction_strategy', None) is not None or pipe.transaction Try / catch
from redis.exceptions import RedisClusterException
try:
pipe.multi()
except RedisClusterException:
# reopen as transactional
pipe = rc.pipeline(transaction=True) Prevention
- Open transactional pipelines with transaction=True up front.
- Remove explicit .multi() calls when porting to cluster.
When it happens
Trigger: Calling pipe.multi() on a ClusterPipeline that was not opened as a transaction: rc.pipeline(transaction=False) or the default non-transactional pipeline, then invoking .multi() to start a transaction mid-stream.
Common situations: Copy-paste from standalone redis.Redis pipeline code where .multi() is used explicitly; attempting to start a transaction lazily after queuing non-transactional commands.
Related errors
- Cannot issue a WATCH after a MULTI
- method discard() is not supported outside of transactional…
- method unwatch() is not supported outside of transactional…
- method watch() is not supported outside of transactional…
- All keys involved in a cluster transaction must map to the…
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/402d3db6aefbffb7.
Report an issue: GitHub.
Appendix: source
Thrown at redis/cluster.py:4547
policy_callback = self._pipe._policies_callback_mapping[request_policy]
if request_policy == RequestPolicy.DEFAULT_KEYED:
nodes = policy_callback(command, *args)
elif request_policy == RequestPolicy.MULTI_SHARD:
nodes = policy_callback(*args, **kwargs)
elif request_policy == RequestPolicy.DEFAULT_KEYLESS:
nodes = policy_callback(args[0])
else:
nodes = policy_callback()
if args[0].lower() == "ft.aggregate":
self._aggregate_nodes = nodes
return nodes
def multi(self):
raise RedisClusterException(
"method multi() is not supported outside of transactional context"
)
def discard(self):
raise RedisClusterException(
"method discard() is not supported outside of transactional context"
)
def watch(self, *names):
raise RedisClusterException(
"method watch() is not supported outside of transactional context"
)
def unwatch(self, *names):
raise RedisClusterException(
"method unwatch() is not supported outside of transactional context"
)
View on GitHub (pinned to 6a6b581b48)