{"id":"b6abe73090214557","repo":"redis/redis-py","slug":"method-discard-is-not-supported-outside-of-trans-b6abe7","errorCode":null,"errorMessage":"method discard() is not supported outside of transactional context","messagePattern":"method discard\\(\\) is not supported outside of transactional context","errorType":"exception","errorClass":"RedisClusterException","httpStatus":null,"severity":"error","filePath":"redis/cluster.py","lineNumber":4530,"sourceCode":"        elif request_policy == RequestPolicy.MULTI_SHARD:\n            nodes = policy_callback(*args, **kwargs)\n        elif request_policy == RequestPolicy.DEFAULT_KEYLESS:\n            nodes = policy_callback(args[0])\n        else:\n            nodes = policy_callback()\n\n        if args[0].lower() == \"ft.aggregate\":\n            self._aggregate_nodes = nodes\n\n        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            )","sourceCodeStart":4512,"sourceCodeEnd":4548,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/cluster.py#L4512-L4548","documentation":"PipelineStrategy.discard() (redis/cluster.py:4529) always raises. DISCARD aborts a MULTI transaction; on a non-transactional pipeline (transaction=False) there is no transaction to abort, so the call is invalid. The strategy is selected at ClusterPipeline.__init__ (redis/cluster.py:3598).","triggerScenarios":"Calling pipe.discard() on a pipeline created with rc.pipeline(transaction=False).","commonSituations":"Reusable error-handling code that calls discard() to clean up a pipeline, run against a non-transactional pipeline. Cleanup/finally blocks that blindly discard. Migrating standalone patterns that use DISCARD defensively.","solutions":["Guard discard() behind the transaction mode, or only call it on a transactional pipeline.","For a non-transactional pipeline, clear queued commands with pipe.reset() instead of discard().","Use rc.pipeline() (default transaction=True) if you need MULTI/DISCARD semantics."],"exampleFix":"# before\npipe = rc.pipeline(transaction=False)\ntry:\n    pipe.discard()  # raises\n\n# after\npipe = rc.pipeline(transaction=False)\npipe.reset()  # safe way to clear a non-transactional pipeline","handlingStrategy":"validation","validationCode":"def safe_discard(pipe):\n    # discard() is only valid on a transactional pipeline\n    if not getattr(pipe, '_execution_strategy', None).__class__.__name__ == 'TransactionStrategy':\n        pipe.reset()  # non-transactional: just clear the queue\n        return\n    pipe.discard()","typeGuard":null,"tryCatchPattern":"from redis.exceptions import RedisClusterException\n\ntry:\n    pipe.discard()\nexcept RedisClusterException:\n    pipe.reset()","preventionTips":["Use pipe.reset() to clear a non-transactional pipeline; reserve discard() for transactions.","Guard cleanup blocks with the pipeline mode.","Default to transaction=True if your cleanup code relies on DISCARD."],"tags":["cluster","pipeline","transaction","api-misuse"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}