redis/redis-py · error · RedisClusterException

method multi() is not supported outside of transactional con

Error message

method multi() is not supported outside of transactional context

What it means

Raised unconditionally by PipelineStrategy.multi() — the non-transactional cluster pipeline strategy. In cluster mode a transactional pipeline is selected by passing transaction=True to rc.pipeline(); without it, the pipeline is fire-and-forget across shards and has no MULTI/EXEC context, so calling multi() on it is meaningless and is rejected.

Source

Thrown at redis/asyncio/cluster.py:3032

                    # Note: when the error is raised we'll reset the default node in the
                    # caller function.
                    for cmd in default_node[1]:
                        # Check if it has a command that failed with a relevant
                        # exception
                        if type(cmd.result) in RedisCluster.ERRORS_ALLOW_RETRY:
                            client.replace_default_node()
                            break

        return [cmd.result for cmd in stack]

    async def reset(self):
        """
        Reset back to empty pipeline.
        """
        self._command_queue = []

    def multi(self):
        raise RedisClusterException(
            "method multi() is not supported outside of transactional context"
        )

    async def watch(self, *names):
        raise RedisClusterException(
            "method watch() is not supported outside of transactional context"
        )

    async def unwatch(self):
        raise RedisClusterException(
            "method unwatch() is not supported outside of transactional context"
        )

    async def discard(self):
        raise RedisClusterException(
            "method discard() is not supported outside of transactional context"
        )

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Create the pipeline as transactional: pipe = rc.pipeline(transaction=True), then call pipe.multi() if needed.
  2. If you don't need a transaction, drop the multi() call — the non-transactional pipeline executes queued commands directly.
  3. Use rc.pipeline(transaction=True) and let the strategy manage MULTI/EXEC automatically rather than calling multi() yourself.

Example fix

// before
pipe = rc.pipeline()
pipe.multi()  # raises

// after
pipe = rc.pipeline(transaction=True)
pipe.multi()
Defensive patterns

Strategy: validation

Validate before calling

def transactional_pipeline(rc, transaction=True):
    pipe = rc.pipeline(transaction=transaction)
    if transaction:
        pipe.multi()  # only valid on the transactional strategy
    return pipe

Type guard

from redis.asyncio.cluster import PipelineStrategy, TransactionStrategy

def supports_multi(pipe) -> bool:
    return isinstance(pipe._strategy, TransactionStrategy)

Try / catch

from redis.cluster import RedisClusterException

try:
    pipe.multi()
except RedisClusterException as e:
    if 'multi()' in str(e):
        pipe = rc.pipeline(transaction=True)
        pipe.multi()
    else:
        raise

Prevention

When it happens

Trigger: Calling pipe.multi() on a pipeline created via rc.pipeline() or rc.pipeline(transaction=False). Only the TransactionStrategy (rc.pipeline(transaction=True)) supports multi(); the default PipelineStrategy raises immediately.

Common situations: Porting standalone Redis pipeline code (where multi() is used to start a transaction) to cluster mode without transaction=True; calling multi() twice; mixing the two pipeline flavors.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/5f8f4e6c76a6c5f4.json. Report an issue: GitHub.