redis/redis-py · error · WatchError
A {type(error).__name__} occurred while watching one or more
Error message
A {type(error).__name__} occurred while watching one or more keys What it means
Raised in `Pipeline._disconnect_reset_raise_on_watching` (the immediate-execution path used for WATCH and pre-MULTI commands). When a retryable connection error occurs while executing a WATCH-time command and retries are exhausted, the connection is disconnected; because the pipeline was in a watching state, the watch is invalidated and a WatchError is raised with the underlying error's type name so the caller knows the transaction must be retried.
Source
Thrown at redis/client.py:1936
"""
if error and failure_count <= conn.retry.get_retries():
record_operation_duration(
command_name=command_name,
duration_seconds=time.monotonic() - start_time,
server_address=getattr(conn, "host", None),
server_port=getattr(conn, "port", None),
db_namespace=str(conn.db),
error=error,
retry_attempts=failure_count,
)
conn.disconnect()
# if we were already watching a variable, the watch is no longer
# valid since this connection has died. raise a WatchError, which
# indicates the user should retry this transaction.
if self.watching:
self.reset()
raise WatchError(
f"A {type(error).__name__} occurred while watching one or more keys"
)
def immediate_execute_command(self, *args, **options):
"""
Execute a command immediately, but don't auto-retry on the supported
errors for retry if we're already WATCHing a variable.
Used when issuing WATCH or subsequent commands retrieving their values but before
MULTI is called.
"""
command_name = args[0]
conn = self.connection
# if this is the first call, we need a connection
if not conn:
conn = self.connection_pool.get_connection()
self.connection = conn
# Start timing for observabilityView on GitHub (pinned to da03cdc7e8)
Solutions
- Wrap WATCH/EXEC blocks in a retry loop that catches WatchError and re-runs the whole transaction.
- Increase `Retry(retries=N)` / tune backoff so transient connection errors are absorbed before the watch is invalidated.
- Stabilize the connection to the Redis server (network, timeouts, pool size).
- Keep the WATCH->read->MULTI->commands->EXEC window short to minimize exposure to disconnects.
Example fix
# before
with client.pipeline() as pipe:
try:
pipe.watch('k')
v = pipe.get('k')
pipe.multi()
pipe.set('k', int(v) + 1)
pipe.execute()
except WatchError:
pass # silently drops the increment on disconnect
# after
for _ in range(10):
try:
with client.pipeline() as pipe:
pipe.watch('k')
v = pipe.get('k')
pipe.multi()
pipe.set('k', int(v) + 1)
pipe.execute()
break
except WatchError:
continue Defensive patterns
Strategy: retry
Try / catch
from redis.exceptions import WatchError
for _ in range(5):
try:
with client.pipeline() as pipe:
pipe.watch('k')
val = pipe.get('k')
pipe.multi()
pipe.set('k', transform(val))
pipe.execute()
break
except WatchError:
continue # retry whole transaction Prevention
- Always wrap WATCH+EXEC in a retry loop catching WatchError.
- Tune Retry(backoff, retries) to absorb transient connection errors.
- Keep the WATCH->EXEC window short.
When it happens
Trigger: Issuing `pipe.watch('k')` followed by a read (e.g. `pipe.get('k')`) on a flaky connection — the immediate_execute_command path is used. If the connection fails after all retries, `_disconnect_reset_raise_on_watching` resets the pipeline and raises `WatchError: A <ErrorType> occurred while watching one or more keys`.
Common situations: Network partitions or Redis restarts during an optimistic-locking transaction; connection pool churn under load; misconfigured retry/backoff giving up too early.
Related errors
- A {type(error).__name__} occurred while watching one or more
- method watch() is not supported outside of transactional con
- Cannot issue a WATCH after a MULTI
- Slot rebalancing occurred while watching keys
- Watched variable changed.
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/6a35164693400796.json.
Report an issue: GitHub.