redis/redis-py · error · RedisError
For "stable" state please use cluster_setslot_stable
Error message
For "stable" state please use cluster_setslot_stable
What it means
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.
Source
Thrown at redis/commands/cluster.py:888
) -> Awaitable[bool]: ...
def cluster_setslot(
self, target_node: "TargetNodesT", node_id: str, slot_id: int, state: str
) -> bool | Awaitable[bool]:
"""
Bind an hash slot to a specific node
:target_node: 'ClusterNode'
The node to execute the command on
For more information see https://redis.io/commands/cluster-setslot
"""
if state.upper() in ("IMPORTING", "NODE", "MIGRATING"):
return self.execute_command(
"CLUSTER SETSLOT", slot_id, state, node_id, target_nodes=target_node
)
elif state.upper() == "STABLE":
raise RedisError('For "stable" state please use cluster_setslot_stable')
else:
raise RedisError(f"Invalid slot state: {state}")
@overload
def cluster_setslot_stable(self: SyncClientProtocol, slot_id: int) -> bool: ...
@overload
def cluster_setslot_stable(
self: AsyncClientProtocol, slot_id: int
) -> Awaitable[bool]: ...
def cluster_setslot_stable(self, slot_id: int) -> bool | Awaitable[bool]:
"""
Clears migrating / importing state from the slot.
It determines by it self what node the slot is in and sends it there.
For more information see https://redis.io/commands/cluster-setslot
"""View on GitHub (pinned to da03cdc7e8)
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.
Example fix
# before r.cluster_setslot(target_node, node_id, slot_id, state='STABLE') # after r.cluster_setslot_stable(slot_id)
Defensive patterns
Strategy: validation
Validate before calling
if str(state).upper() == 'STABLE':
# do not call cluster_setslot; route to the dedicated method
client.cluster_setslot_stable(slot_id)
else:
client.cluster_setslot(target_node, node_id, slot_id, state=state) Type guard
def is_directed_state(state: str) -> bool:
return str(state).upper() in {'IMPORTING', 'NODE', 'MIGRATING'} Try / catch
from redis.exceptions import RedisError
try:
client.cluster_setslot(target_node, node_id, slot_id, state=state)
except RedisError as e:
if 'cluster_setslot_stable' in str(e):
client.cluster_setslot_stable(slot_id)
else:
raise Prevention
- Special-case STABLE in any state-driven reshard helper.
- Read the method's docstring before calling — it documents the redirect.
When it happens
Trigger: 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'.
Common situations: 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.
Related errors
- Invalid slot state: {state}
- Subcommand {subcommand_name} not found in command {command_n
- Command {command_name} not found in commands
- Invalid option for CLUSTER FAILOVER command: {option}
- {cmd_name.upper()} command doesn't exist in Redis commands
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/adab4d396c75672e.json.
Report an issue: GitHub.