{"record":{"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/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/cluster.py#L870-L906","documentation":"Raised by ClusterManagementCommands.cluster_setslot() in redis/commands/cluster.py:888 when the state argument is 'STABLE'. The library splits CLUSTER SETSLOT into two methods because the STABLE state does not require a node_id argument, so it routes you to cluster_setslot_stable(slot_id) which has the correct signature.","triggerScenarios":"Calling rc.cluster_setslot(target_node, node_id, slot_id, state='STABLE'), or passing state='stable' (case-insensitive match).","commonSituations":"Generic slot-management code that handles all states in one call; copy-paste of the IMPORTING/MIGRATING/NODE call with state swapped to STABLE without dropping node_id.","solutions":["For the STABLE state call rc.cluster_setslot_stable(slot_id) instead.","Only pass state in {'IMPORTING','NODE','MIGRATING'} to cluster_setslot().","Refactor generic slot code to branch: if state.upper()=='STABLE': use cluster_setslot_stable()."],"exampleFix":"// before\nrc.cluster_setslot(node, node_id, slot_id, 'STABLE')\n// after\nrc.cluster_setslot_stable(slot_id)","handlingStrategy":"validation","validationCode":"if state.strip().upper() == 'STABLE':\n    rc.cluster_setslot_stable(slot_id)\nelse:\n    rc.cluster_setslot(target_node, node_id, slot_id, state)","typeGuard":"def is_stable_state(state) -> bool:\n    return isinstance(state, str) and state.strip().upper() == 'STABLE'","tryCatchPattern":"from redis.exceptions import RedisError\ntry:\n    rc.cluster_setslot(node, node_id, slot_id, state)\nexcept RedisError as e:\n    if 'stable\" state' in str(e):\n        rc.cluster_setslot_stable(slot_id)","preventionTips":["Branch on state=='STABLE' to call cluster_setslot_stable().","Only pass IMPORTING/NODE/MIGRATING to cluster_setslot()."],"tags":["cluster","slot-management","api-misuse","validation"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}