{"record":{"id":"a04ae81a131a3dac","repo":"redis/redis-py","slug":"slot-rebalancing-occurred-while-watching-keys","errorCode":null,"errorMessage":"Slot rebalancing occurred while watching keys","messagePattern":"Slot rebalancing occurred while watching keys","errorType":"exception","errorClass":"WatchError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/cluster.py","lineNumber":3303,"sourceCode":"        if command_name in self.UNWATCH_COMMANDS:\n            self._watching = False\n        return output\n\n    async def _reinitialize_on_error(self, error, failure_count):\n        if hasattr(error, \"connection\"):\n            await record_error_count(\n                server_address=error.connection.host,\n                server_port=error.connection.port,\n                network_peer_address=error.connection.host,\n                network_peer_port=error.connection.port,\n                error_type=error,\n                retry_attempts=failure_count,\n                is_internal=True,\n            )\n\n        if self._watching:\n            if type(error) in self.SLOT_REDIRECT_ERRORS and self._executing:\n                raise WatchError(\"Slot rebalancing occurred while watching keys\")\n\n        if (\n            type(error) in self.SLOT_REDIRECT_ERRORS\n            or type(error) in self.CONNECTION_ERRORS\n        ):\n            if self._transaction_connection and self._transaction_node:\n                # Disconnect and release back to pool\n                await self._transaction_connection.disconnect()\n                self._transaction_node.release(self._transaction_connection)\n                self._transaction_connection = None\n\n            self._pipe.cluster_client.reinitialize_counter += 1\n            if (\n                self._pipe.cluster_client.reinitialize_steps\n                and self._pipe.cluster_client.reinitialize_counter\n                % self._pipe.cluster_client.reinitialize_steps\n                == 0\n            ):","sourceCodeStart":3285,"sourceCodeEnd":3321,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/cluster.py#L3285-L3321","documentation":"WatchError raised in TransactionStrategy._reinitialize_on_error (redis/asyncio/cluster.py:3303) when an ASK or MOVED redirect arrives while WATCH is active and the transaction is mid-execution. A slot move invalidates the watched-key connection pinning (WATCH state is connection-local), so the transaction cannot transparently retry. The caller must redo the whole watch/transaction sequence.","triggerScenarios":"A cluster reshard, failover, or slot migration is in progress while a watched transaction runs, producing an ASK/MOVED error during EXEC.","commonSituations":"Operating against a cluster undergoing scaling operations; long-running transactions that outlast a rebalance window.","solutions":["Wrap the watch/multi/exec sequence in a retry loop that re-runs WATCH + transaction on WatchError","Pause or avoid cluster reshard during critical transactions","Use optimistic concurrency at the application level (version checks) instead of WATCH under unstable topology"],"exampleFix":"// before\nawait pipe.watch('k1')\n...multi/exec...\n// after\nfor _ in range(retries):\n    try:\n        await pipe.watch('k1')\n        ...multi/exec...\n        break\n    except WatchError:\n        await pipe.reset()","handlingStrategy":"retry","validationCode":"# cannot fully prevent; topology is external. Detect and retry.\nfrom redis.exceptions import WatchError","typeGuard":null,"tryCatchPattern":"for _ in range(MAX_RETRIES):\n    try:\n        await pipe.watch('k1'); pipe.multi(); ...; await pipe.execute(); break\n    except WatchError:\n        await pipe.reset()","preventionTips":["Always retry the full WATCH/transaction sequence on WatchError","Avoid running transactions during scheduled reshard windows"],"tags":["cluster","pipeline","transaction","watch","resharding","retry"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}