{"id":"adab4d396c75672e","repo":"redis/redis-py","slug":"for-stable-state-please-use-cluster-setslot-stab","errorCode":null,"errorMessage":"For \"stable\" state please use cluster_setslot_stable","messagePattern":"For \"stable\" state please use cluster_setslot_stable","errorType":"exception","errorClass":"RedisError","httpStatus":null,"severity":"error","filePath":"redis/commands/cluster.py","lineNumber":888,"sourceCode":"    ) -> Awaitable[bool]: ...\n\n    def cluster_setslot(\n        self, target_node: \"TargetNodesT\", node_id: str, slot_id: int, state: str\n    ) -> bool | Awaitable[bool]:\n        \"\"\"\n        Bind an hash slot to a specific node\n\n        :target_node: 'ClusterNode'\n            The node to execute the command on\n\n        For more information see https://redis.io/commands/cluster-setslot\n        \"\"\"\n        if state.upper() in (\"IMPORTING\", \"NODE\", \"MIGRATING\"):\n            return self.execute_command(\n                \"CLUSTER SETSLOT\", slot_id, state, node_id, target_nodes=target_node\n            )\n        elif state.upper() == \"STABLE\":\n            raise RedisError('For \"stable\" state please use cluster_setslot_stable')\n        else:\n            raise RedisError(f\"Invalid slot state: {state}\")\n\n    @overload\n    def cluster_setslot_stable(self: SyncClientProtocol, slot_id: int) -> bool: ...\n\n    @overload\n    def cluster_setslot_stable(\n        self: AsyncClientProtocol, slot_id: int\n    ) -> Awaitable[bool]: ...\n\n    def cluster_setslot_stable(self, slot_id: int) -> bool | Awaitable[bool]:\n        \"\"\"\n        Clears migrating / importing state from the slot.\n        It determines by it self what node the slot is in and sends it there.\n\n        For more information see https://redis.io/commands/cluster-setslot\n        \"\"\"","sourceCodeStart":870,"sourceCodeEnd":906,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/cluster.py#L870-L906","documentation":"Raised by cluster_setslot() when the caller passes state='STABLE'. The method only handles IMPORTING, NODE, and MIGRATING states itself; the STABLE case has a dedicated method (cluster_setslot_stable) that auto-resolves the target node, so this RedisError redirects you there rather than silently guessing a node. It is a usage/API-routing error, not a server-side failure.","triggerScenarios":"Calling r.cluster_setslot(target_node, node_id, slot_id, state='STABLE') (any case of 'stable') on a RedisCluster / Redis client. The STABLE branch at redis/commands/cluster.py:887 fires the moment state.upper() == 'STABLE'.","commonSituations":"Porting a raw 'CLUSTER SETSLOT <slot> STABLE' workflow into the python client verbatim; scripted reshard/drain tooling that loops over all four states uniformly; copying example code that uses the generic server syntax.","solutions":["Replace the cluster_setslot(..., state='STABLE') call with cluster_setslot_stable(slot_id), which needs no node_id or target_node.","If you must branch on state in code, special-case STABLE to call cluster_setslot_stable and pass only IMPORTING/NODE/MIGRATING to cluster_setslot.","Verify you actually need STABLE at all during a reshard — it is usually invoked automatically by the client once a slot migration completes."],"exampleFix":"# before\nr.cluster_setslot(target_node, node_id, slot_id, state='STABLE')\n# after\nr.cluster_setslot_stable(slot_id)","handlingStrategy":"validation","validationCode":"if str(state).upper() == 'STABLE':\n    # do not call cluster_setslot; route to the dedicated method\n    client.cluster_setslot_stable(slot_id)\nelse:\n    client.cluster_setslot(target_node, node_id, slot_id, state=state)","typeGuard":"def is_directed_state(state: str) -> bool:\n    return str(state).upper() in {'IMPORTING', 'NODE', 'MIGRATING'}","tryCatchPattern":"from redis.exceptions import RedisError\ntry:\n    client.cluster_setslot(target_node, node_id, slot_id, state=state)\nexcept RedisError as e:\n    if 'cluster_setslot_stable' in str(e):\n        client.cluster_setslot_stable(slot_id)\n    else:\n        raise","preventionTips":["Special-case STABLE in any state-driven reshard helper.","Read the method's docstring before calling — it documents the redirect."],"tags":["cluster","setslot","api-routing","validation"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}