redis/redis-py · error · RedisClusterException
method discard() is not supported outside of transactional c
Error message
method discard() is not supported outside of transactional context
What it means
Raised unconditionally by PipelineStrategy.discard() — the non-transactional cluster pipeline strategy. DISCARD aborts a MULTI transaction; a non-transactional cluster pipeline has no transaction to discard, so the call is rejected. To clear a non-transactional pipeline's queued commands, use reset() instead.
Source
Thrown at redis/asyncio/cluster.py:3047
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"
)
return self.execute_command("UNLINK", names[0])
class TransactionStrategy(AbstractStrategy):
NO_SLOTS_COMMANDS = {"UNWATCH"}
IMMEDIATE_EXECUTE_COMMANDS = {"WATCH", "UNWATCH"}
UNWATCH_COMMANDS = {"DISCARD", "EXEC", "UNWATCH"}
SLOT_REDIRECT_ERRORS = (AskError, MovedError)
CONNECTION_ERRORS = (View on GitHub (pinned to da03cdc7e8)
Solutions
- For a non-transactional pipeline, call await pipe.reset() to clear queued commands instead of discard().
- If you need true transactional DISCARD semantics, use pipe = rc.pipeline(transaction=True).
- Restructure error handlers so discard() only runs when transaction=True was used.
Example fix
// before pipe = rc.pipeline() await pipe.discard() # raises // after pipe = rc.pipeline() await pipe.reset()
Defensive patterns
Strategy: validation
Validate before calling
async def clear_pipeline(pipe):
if getattr(pipe, '_transaction', False):
await pipe.discard()
else:
await pipe.reset() Type guard
from redis.asyncio.cluster import TransactionStrategy
def supports_discard(pipe) -> bool:
return isinstance(getattr(pipe, '_strategy', None), TransactionStrategy) Try / catch
from redis.cluster import RedisClusterException
try:
await pipe.discard()
except RedisClusterException as e:
if 'discard()' in str(e):
await pipe.reset() # non-transactional equivalent
else:
raise Prevention
- Use reset() to clear a non-transactional pipeline; reserve discard() for transactional ones.
- Branch cleanup logic on the pipeline's transaction flag.
- Document which pipeline flavor each helper targets.
When it happens
Trigger: Calling await pipe.discard() on a pipeline created via rc.pipeline() or rc.pipeline(transaction=False). Transactional pipelines (transaction=True) support discard.
Common situations: Porting standalone pipeline abort logic to cluster mode; calling discard() in error-handling code on the wrong pipeline flavor; expecting DISCARD to clear a non-transactional command queue.
Related errors
- method multi() is not supported outside of transactional con
- method watch() is not supported outside of transactional con
- method unwatch() is not supported outside of transactional c
- shard_hint is deprecated in cluster mode
- No targets were found to execute {cmd.args} command on
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/3efcc5de19a87184.json.
Report an issue: GitHub.