redis/redis-py · error · RedisClusterException
method watch() is not supported outside of transactional…
Error message
method watch() is not supported outside of transactional context
What it means
ClusterPipeline.watch() raises unconditionally in the non-transactional PipelineStrategy. WATCH is a transaction primitive that must be issued inside a transactional context against a single node; the default non-transactional cluster pipeline cannot honour it, so the call is rejected.
Solutions
- Use rc.pipeline(transaction=True) which wires up WATCH through the transactional strategy.
- For cluster-wide optimistic locking, restrict watched keys to a single slot (shared hash tag) so a one-node WATCH is valid.
- If you only need batching without transactions, drop the watch() call entirely.
Example fix
// before
pipe = rc.pipeline()
await pipe.watch('account:1') # raises
// after
pipe = rc.pipeline(transaction=True)
await pipe.watch('{acct}:1')
pipe.multi() # supported inside transactional strategy
pipe.decrby('{acct}:1', 10)
await pipe.execute() Defensive patterns
Strategy: validation
Validate before calling
async def cluster_watch(rc, key):
pipe = rc.pipeline(transaction=True)
await pipe.watch(key) # valid only in transactional pipeline
return pipe Type guard
null
Try / catch
from redis.exceptions import RedisClusterException
try:
await pipe.watch(key)
except RedisClusterException as e:
if 'watch() is not supported' in str(e):
pipe = rc.pipeline(transaction=True)
await pipe.watch(key) Prevention
- Use rc.pipeline(transaction=True) before calling watch().
- Keep watched keys under one hash tag so they sit on one node.
- Drop watch() from non-transactional batching pipelines.
When it happens
Trigger: Calling await pipe.watch('key') on a pipeline created with rc.pipeline() (transaction defaults False). The method exists on the class only to satisfy the abstract strategy interface.
Common situations: Migrating optimistic-locking code (WATCH/MULTI/EXEC) from the standalone client to the cluster client without enabling transaction mode; calling watch() on a pipeline you intend to use purely for batching.
Related errors
- Cannot identify slot number for command
- Cannot issue a WATCH after a MULTI
- Cannot watch or send commands on different slots
- Slot rebalancing occurred while watching keys
- Watched variable changed.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/ead0dfefabaa8fbb.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/cluster.py:3038
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"
)
async def unlink(self, *names):
if len(names) != 1:
raise RedisClusterException(
"unlinking multiple keys is not implemented in pipeline command"
)View on GitHub (pinned to 6a6b581b48)