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

  1. Retry the whole WATCH/MULTI/EXEC sequence from the top — the client will refresh slot maps on the next initialize().
  2. Keep watched transactions short to shrink the window during which a reshard can interfere.
  3. 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

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


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/a04ae81a131a3dac.json. Report an issue: GitHub.