redis/redis-py · error · RedisError
Commands without an initial WATCH have already been issued
Error message
Commands without an initial WATCH have already been issued
What it means
Raised in `Pipeline.multi()` when `self.command_stack` is non-empty. The explicit-multi workflow requires WATCH (or nothing) to be issued before MULTI; queuing regular commands first and then calling `multi()` is rejected because those commands were already buffered as a non-transactional pipeline. The library refuses to silently convert a plain pipeline into a transaction.
Source
Thrown at redis/client.py:1891
# we can safely return the connection to the pool here since we're
# sure we're no longer WATCHing anything
if self.connection:
self.connection_pool.release(self.connection)
self.connection = None
def close(self) -> None:
"""Close the pipeline"""
self.reset()
def multi(self) -> None:
"""
Start a transactional block of the pipeline after WATCH commands
are issued. End the transactional block with `execute`.
"""
if self.explicit_transaction:
raise RedisError("Cannot issue nested calls to MULTI")
if self.command_stack:
raise RedisError(
"Commands without an initial WATCH have already been issued"
)
self.explicit_transaction = True
def execute_command(self, *args, **kwargs):
if (self.watching or args[0] == "WATCH") and not self.explicit_transaction:
return self.immediate_execute_command(*args, **kwargs)
return self.pipeline_execute_command(*args, **kwargs)
def _disconnect_reset_raise_on_watching(
self,
conn: AbstractConnection,
error: Exception,
failure_count: Optional[int] = None,
start_time: Optional[float] = None,
command_name: Optional[str] = None,
) -> None:
"""View on GitHub (pinned to da03cdc7e8)
Solutions
- Reorder: issue `pipe.multi()` (after optional `pipe.watch(...)`) before queuing any commands.
- If you intended a plain (non-transactional) pipeline, simply omit the multi() call — execute() will run the buffered commands.
- Create a new pipeline if you need to switch from plain to transactional mode.
Example fix
# before
pipe = client.pipeline()
pipe.set('a', 1)
pipe.multi() # raises: Commands without an initial WATCH have already been issued
# after
pipe = client.pipeline()
pipe.multi()
pipe.set('a', 1)
pipe.execute() Defensive patterns
Strategy: validation
Validate before calling
# Enforce ordering: multi() must precede any queued commands
pipe = client.pipeline()
pipe.multi() # call BEFORE queuing commands
pipe.set('a', 1) Try / catch
from redis.exceptions import RedisError
try:
pipe.multi()
except RedisError as e:
if 'Commands without an initial WATCH' in str(e):
# start over with a new pipeline in the correct order
pipe = client.pipeline(); pipe.multi()
else:
raise Prevention
- Always issue multi() before any command when you want a transaction.
- Create a new pipeline if you need to switch modes.
When it happens
Trigger: Calling `pipe.set('a', 1)` (or any command) BEFORE `pipe.multi()`. Once the command_stack has entries, multi() is disallowed. The correct order is: optional `pipe.watch(...)`, then `pipe.multi()`, then the queued commands.
Common situations: Misunderstanding the WATCH->MULTI->commands->EXEC ordering; refactoring a plain pipeline into a transactional one without moving the multi() call to the front.
Related errors
- Cannot issue a WATCH after a MULTI
- Cannot issue a WATCH after a MULTI
- Cannot issue a WATCH after a MULTI
- method multi() is not supported outside of transactional con
- method watch() is not supported outside of transactional con
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/4547849dce7bfaa7.json.
Report an issue: GitHub.