redis/redis-py · error · RedisClusterException

method discard() is not supported outside of transactional…

Error message

method discard() is not supported outside of transactional context

What it means

Raised by AbstractStrategy.discard() in redis/cluster.py:4552. DISCARD aborts a MULTI transaction, but a non-transactional cluster pipeline never entered MULTI, so there is nothing to discard. The cluster pipeline exposes discard only on its transactional strategy path.

Solutions

  1. Only call discard() inside a transactional pipeline (rc.pipeline(transaction=True)) after MULTI was implicitly started.
  2. For a non-transactional pipeline, call pipe.reset() to clear the command queue instead of discard().
  3. Guard the discard call so it only runs when a transaction is actually in progress.

Example fix

// before
pipe = rc.pipeline()
try:
    pipe.set('k', 'v')
    pipe.discard()
// after
pipe = rc.pipeline()
pipe.reset()  # clear non-transactional queue
Defensive patterns

Strategy: validation

Validate before calling

if getattr(pipe, 'transaction', False):
    pipe.discard()
else:
    pipe.reset()

Type guard

def is_transactional_pipe(pipe) -> bool:
    return bool(getattr(pipe, 'transaction', False))

Try / catch

from redis.exceptions import RedisClusterException
try:
    pipe.discard()
except RedisClusterException:
    pipe.reset()

Prevention

When it happens

Trigger: Calling pipe.discard() on a non-transactional ClusterPipeline (rc.pipeline(transaction=False) or default), or calling discard before multi/transaction was started.

Common situations: Standalone pipeline code ported to cluster; exception handlers that unconditionally call pipe.discard() to clean up.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/b6abe73090214557. Report an issue: GitHub.

Appendix: source

Thrown at redis/cluster.py:4552

        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"
        )

    def delete(self, *names):
        if len(names) != 1:
            raise RedisClusterException(
                "deleting multiple keys is not implemented in pipeline command"
            )

View on GitHub (pinned to 6a6b581b48)