redis/redis-py · error · RedisClusterException

method unwatch() is not supported outside of transactional c

Error message

method unwatch() is not supported outside of transactional context

What it means

PipelineStrategy.unwatch() (redis/cluster.py:4539) always raises. UNWATCH clears keys watched in a transactional context; on a non-transactional pipeline (transaction=False) there is nothing watched and the call is invalid.

Source

Thrown at redis/cluster.py:4540

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

        return self.execute_command("DEL", names[0])

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

        return self.execute_command("UNLINK", names[0])

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Only call unwatch() on a transactional pipeline (rc.pipeline(transaction=True)).
  2. For a non-transactional pipeline, simply reset() or let it go out of scope; no watch state exists to clear.
  3. Guard unwatch() with the pipeline mode when sharing code between modes.

Example fix

# before
pipe = rc.pipeline(transaction=False)
pipe.unwatch()  # raises

# after
pipe = rc.pipeline(transaction=True)
pipe.watch('k')
pipe.unwatch()  # valid on a transactional pipeline
Defensive patterns

Strategy: validation

Validate before calling

def safe_unwatch(pipe):
    if getattr(pipe, '_execution_strategy', None).__class__.__name__ != 'TransactionStrategy':
        return  # nothing watched on a non-transactional pipeline
    pipe.unwatch()

Try / catch

from redis.exceptions import RedisClusterException

try:
    pipe.unwatch()
except RedisClusterException:
    pass  # nothing to clear on a non-transactional pipeline

Prevention

When it happens

Trigger: Calling pipe.unwatch() on a pipeline created with rc.pipeline(transaction=False). Note ClusterPipeline.unwatch (redis/cluster.py:3738) takes no arguments, while the raising stub declares unwatch(self, *names) — the call still lands on the stub regardless of arguments.

Common situations: Cleanup code that calls unwatch() in a finally block, run against a non-transactional pipeline. Standalone pipeline patterns reused in cluster code with transaction disabled.

Related errors


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