redis/redis-py · error · RedisClusterException
method watch() is not supported outside of transactional con
Error message
method watch() is not supported outside of transactional context
What it means
PipelineStrategy.watch() (redis/cluster.py:4534) always raises. WATCH provides optimistic locking for a MULTI/EXEC transaction; it is meaningless on a non-transactional pipeline (transaction=False), which is why the non-transactional strategy rejects it.
Source
Thrown at redis/cluster.py:4535
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"
)
return self.execute_command("DEL", names[0])
def unlink(self, *names):
if len(names) != 1:View on GitHub (pinned to da03cdc7e8)
Solutions
- Use a transactional pipeline for WATCH: rc.pipeline(transaction=True), and ensure all watched keys share a hash slot.
- If you must run transaction=False, drop WATCH and implement optimistic locking another way (e.g. compare-and-set via Lua on the client).
- Branch code on the pipeline mode so watch() is only invoked transactionally.
Example fix
# before
pipe = rc.pipeline(transaction=False)
pipe.watch('user:1') # raises
# after
pipe = rc.pipeline(transaction=True)
pipe.watch('user:1')
pipe.multi()
pipe.set('user:1', 'alice')
pipe.execute() Defensive patterns
Strategy: validation
Validate before calling
def watch_keys(client, *keys, transaction=True):
if not transaction:
raise ValueError('WATCH requires a transactional pipeline (transaction=True)')
pipe = client.pipeline(transaction=True)
pipe.watch(*keys)
return pipe Try / catch
from redis.exceptions import RedisClusterException
try:
pipe.watch('k')
except RedisClusterException:
pipe = rc.pipeline(transaction=True)
pipe.watch('k') Prevention
- Always create the pipeline with transaction=True before WATCH.
- Ensure all watched keys share a hash tag so they fall in one slot.
- Avoid transaction=False for any optimistic-locking code path.
When it happens
Trigger: Calling pipe.watch('key') on a pipeline created with rc.pipeline(transaction=False). The call routes ClusterPipeline.watch (redis/cluster.py:3734) -> PipelineStrategy.watch -> raises at redis/cluster.py:4535.
Common situations: Porting standalone optimistic-locking code (WATCH/MULTI/EXEC) into a cluster app while forcing transaction=False. Shared pipeline helper used by both batched and transactional flows.
Related errors
- method unwatch() is not supported outside of transactional c
- Cannot issue a WATCH after a MULTI
- method watch() is not supported outside of transactional con
- At least a command with a key is needed to identify a node
- Cannot watch or send commands on different slots
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/a2400dd8b38b0853.json.
Report an issue: GitHub.