{"record":{"id":"a91fd7d3b3850ce9","repo":"redis/redis-py","slug":"method-unwatch-is-not-supported-outside-of-trans-a91fd7","errorCode":null,"errorMessage":"method unwatch() is not supported outside of transactional context","messagePattern":"method unwatch\\(\\) is not supported outside of transactional context","errorType":"exception","errorClass":"RedisClusterException","httpStatus":null,"severity":"error","filePath":"redis/cluster.py","lineNumber":4562,"sourceCode":"        return nodes\n\n    def multi(self):\n        raise RedisClusterException(\n            \"method multi() is not supported outside of transactional context\"\n        )\n\n    def discard(self):\n        raise RedisClusterException(\n            \"method discard() is not supported outside of transactional context\"\n        )\n\n    def watch(self, *names):\n        raise RedisClusterException(\n            \"method watch() is not supported outside of transactional context\"\n        )\n\n    def unwatch(self, *names):\n        raise RedisClusterException(\n            \"method unwatch() is not supported outside of transactional context\"\n        )\n\n    def delete(self, *names):\n        if len(names) != 1:\n            raise RedisClusterException(\n                \"deleting multiple keys is not implemented in pipeline command\"\n            )\n\n        return self.execute_command(\"DEL\", names[0])\n\n    def unlink(self, *names):\n        if len(names) != 1:\n            raise RedisClusterException(\n                \"unlinking multiple keys is not implemented in pipeline command\"\n            )\n\n        return self.execute_command(\"UNLINK\", names[0])","sourceCodeStart":4544,"sourceCodeEnd":4580,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/cluster.py#L4544-L4580","documentation":"Raised by AbstractStrategy.unwatch() in redis/cluster.py:4562. UNWATCH clears WATCH markers, but a non-transactional cluster pipeline cannot watch keys in the first place, so unwatch() is meaningless there. Only the TransactionStrategy path handles UNWATCH (it is in IMMEDIATE_EXECUTE_COMMANDS and UNWATCH_COMMANDS).","triggerScenarios":"Calling pipe.unwatch() on a ClusterPipeline that was not opened as a transaction, or calling it outside of any watch context.","commonSituations":"Finally-block cleanup that unconditionally calls unwatch(); standalone pipeline patterns copied to cluster.","solutions":["Only call unwatch() within a transactional pipeline after watch() was used.","Remove the unconditional unwatch() call in non-transactional code paths.","Reset the non-transactional pipeline with pipe.reset() if you need to clear state."],"exampleFix":"// before\npipe = rc.pipeline()\ntry:\n    pipe.set('k', 'v')\nfinally:\n    pipe.unwatch()\n// after\npipe = rc.pipeline()\ntry:\n    pipe.set('k', 'v')\nfinally:\n    pipe.reset()","handlingStrategy":"validation","validationCode":"if getattr(pipe, 'transaction', False) and getattr(pipe, '_watching', False):\n    pipe.unwatch()","typeGuard":"def is_transactional_pipe(pipe) -> bool:\n    return bool(getattr(pipe, 'transaction', False))","tryCatchPattern":"from redis.exceptions import RedisClusterException\ntry:\n    pipe.unwatch()\nexcept RedisClusterException:\n    pass  # nothing to unwatch on non-transactional pipeline","preventionTips":["Only call unwatch() within a transactional pipeline that called watch().","Remove blanket finally-block unwatch() calls."],"tags":["cluster","pipeline","transaction","api-misuse"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}