redis/redis-py · error · WatchError
Slot rebalancing occurred while watching keys
Error message
Slot rebalancing occurred while watching keys
What it means
Raised as WatchError inside _reinitialize_on_error when the pipeline is in WATCH mode, execution is in flight, and a slot-redirect error (MOVED/ASK — i.e. SLOT_REDIRECT_ERRORS) is returned. A redirect means the slot (and therefore the watched key) has moved to a different node mid-transaction; the WATCH state cannot be migrated, so the transaction is aborted.
Source
Thrown at redis/asyncio/cluster.py:3271
if command_name in self.UNWATCH_COMMANDS:
self._watching = False
return output
async def _reinitialize_on_error(self, error, failure_count):
if hasattr(error, "connection"):
await record_error_count(
server_address=error.connection.host,
server_port=error.connection.port,
network_peer_address=error.connection.host,
network_peer_port=error.connection.port,
error_type=error,
retry_attempts=failure_count,
is_internal=True,
)
if self._watching:
if type(error) in self.SLOT_REDIRECT_ERRORS and self._executing:
raise WatchError("Slot rebalancing occurred while watching keys")
if (
type(error) in self.SLOT_REDIRECT_ERRORS
or type(error) in self.CONNECTION_ERRORS
):
if self._transaction_connection and self._transaction_node:
# Disconnect and release back to pool
await self._transaction_connection.disconnect()
self._transaction_node.release(self._transaction_connection)
self._transaction_connection = None
self._pipe.cluster_client.reinitialize_counter += 1
if (
self._pipe.cluster_client.reinitialize_steps
and self._pipe.cluster_client.reinitialize_counter
% self._pipe.cluster_client.reinitialize_steps
== 0
):View on GitHub (pinned to da03cdc7e8)
Solutions
- Retry the whole WATCH/MULTI/EXEC sequence from the top — the client will refresh slot maps on the next initialize().
- Keep watched transactions short to shrink the window during which a reshard can interfere.
- If resharding is ongoing, pause it or run the workload outside the rebalance window.
Example fix
// before (single attempt, fails under reshard)
await pipe.watch('k')
await pipe.multi(); await pipe.set('k','v'); await pipe.execute()
// after (retry the entire block)
for _ in range(retries):
try:
pipe = client.pipeline(transaction=True)
await pipe.watch('k')
await pipe.multi(); await pipe.set('k','v')
await pipe.execute(); break
except WatchError:
continue Defensive patterns
Strategy: retry
Validate before calling
# Nothing to validate pre-flight; resharding is external. Just budget retries. max_reshard_retries = 5
Try / catch
from redis.exceptions import WatchError
for _ in range(max_reshard_retries):
try:
await run_watched_transaction(client)
break
except WatchError as e:
if 'Slot rebalancing' in str(e):
await client.initialize() # refresh slot map
continue
raise Prevention
- Keep WATCH-to-EXEC windows short during cluster scaling.
- Wrap watched transactions in a retry loop that refreshes the slot map.
When it happens
Trigger: A cluster resharding/rebalance happens between WATCH and EXEC of a cluster pipeline transaction; the watched key's slot is migrated to another node and the server replies MOVED/ASK during execution.
Common situations: Long-running watched transactions during cluster scaling operations, slot migrations, or failover; using cluster transactions against a topology that is being actively rebalanced.
Related errors
- Watched variable changed.
- A {type(error).__name__} occurred while watching one or more
- Cannot issue a WATCH after a MULTI
- A {type(error).__name__} occurred while watching one or more
- Watched variable changed.
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/a04ae81a131a3dac.json.
Report an issue: GitHub.