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

  1. Open the pipeline as a transaction from the start: with rc.pipeline(transaction=True) as pipe: ...
  2. Remove the explicit .multi() call; the transactional pipeline handles MULTI implicitly on execute().
  3. 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

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


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)