{"id":"ead0dfefabaa8fbb","repo":"redis/redis-py","slug":"method-watch-is-not-supported-outside-of-transac","errorCode":null,"errorMessage":"method watch() is not supported outside of transactional context","messagePattern":"method watch\\(\\) is not supported outside of transactional context","errorType":"exception","errorClass":"RedisClusterException","httpStatus":null,"severity":"error","filePath":"redis/asyncio/cluster.py","lineNumber":3037,"sourceCode":"                        if type(cmd.result) in RedisCluster.ERRORS_ALLOW_RETRY:\n                            client.replace_default_node()\n                            break\n\n        return [cmd.result for cmd in stack]\n\n    async def reset(self):\n        \"\"\"\n        Reset back to empty pipeline.\n        \"\"\"\n        self._command_queue = []\n\n    def multi(self):\n        raise RedisClusterException(\n            \"method multi() is not supported outside of transactional context\"\n        )\n\n    async def watch(self, *names):\n        raise RedisClusterException(\n            \"method watch() is not supported outside of transactional context\"\n        )\n\n    async def unwatch(self):\n        raise RedisClusterException(\n            \"method unwatch() is not supported outside of transactional context\"\n        )\n\n    async def discard(self):\n        raise RedisClusterException(\n            \"method discard() is not supported outside of transactional context\"\n        )\n\n    async def unlink(self, *names):\n        if len(names) != 1:\n            raise RedisClusterException(\n                \"unlinking multiple keys is not implemented in pipeline command\"\n            )","sourceCodeStart":3019,"sourceCodeEnd":3055,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/asyncio/cluster.py#L3019-L3055","documentation":"Raised unconditionally by PipelineStrategy.watch() — the non-transactional cluster pipeline strategy. WATCH is a Redis optimistic-locking primitive that only makes sense inside a MULTI/EXEC transaction; a non-transactional cluster pipeline has no transactional context, so watch() is not supported there.","triggerScenarios":"Calling await pipe.watch('key') on a pipeline created via rc.pipeline() or rc.pipeline(transaction=False). Transactional pipelines (rc.pipeline(transaction=True)) support WATCH.","commonSituations":"Porting standalone optimistic-locking code to cluster mode without enabling the transactional pipeline; calling watch() for the first time on a freshly created non-transactional pipe.","solutions":["Use a transactional pipeline: pipe = rc.pipeline(transaction=True), then await pipe.watch('key').","If optimistic locking isn't needed, remove the watch() call.","Prefer the cluster lock (redis.lock.Lock) over WATCH/MULTI for distributed mutual exclusion."],"exampleFix":"// before\npipe = rc.pipeline()\nawait pipe.watch('counter')  # raises\n\n// after\npipe = rc.pipeline(transaction=True)\nawait pipe.watch('counter')","handlingStrategy":"validation","validationCode":"def watch_if_transactional(pipe, *keys):\n    if not getattr(pipe, '_transaction', False):\n        raise ValueError('watch() requires rc.pipeline(transaction=True)')\n    return pipe.watch(*keys)","typeGuard":"from redis.asyncio.cluster import TransactionStrategy\n\ndef supports_watch(pipe) -> bool:\n    return isinstance(getattr(pipe, '_strategy', None), TransactionStrategy)","tryCatchPattern":"from redis.cluster import RedisClusterException\n\ntry:\n    await pipe.watch('k')\nexcept RedisClusterException as e:\n    if 'watch()' in str(e):\n        pipe = rc.pipeline(transaction=True)\n        await pipe.watch('k')\n    else:\n        raise","preventionTips":["Use rc.pipeline(transaction=True) for any WATCH-based optimistic locking.","Consider redis.lock.Lock for distributed locking instead of WATCH/MULTI in cluster mode.","Keep transactional pipeline helpers separate from fire-and-forget pipelines."],"tags":["redis-cluster","pipeline","transaction","watch","optimistic-locking"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}