redis/redis-py · error · RedisError
Invalid slot state: {state}
Error message
Invalid slot state: {state} What it means
Raised by cluster_setslot() when the state argument is not one of IMPORTING, NODE, MIGRATING, or STABLE. It is a client-side argument-validation guard (RedisError) fired before any command is sent to the server, so the slot is never touched. The invalid value is interpolated into the message to help spot typos or unexpected enums.
Source
Thrown at redis/commands/cluster.py:890
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
"""
return self.execute_command("CLUSTER SETSLOT", slot_id, "STABLE")
View on GitHub (pinned to da03cdc7e8)
Solutions
- Pass one of 'IMPORTING', 'NODE', 'MIGRATING' (or 'STABLE', but then prefer cluster_setslot_stable).
- Validate/normalize the state against an allow-list before calling cluster_setslot.
- Check the source of the state value for truncation or wrong casing.
Example fix
# before
r.cluster_setslot(node, node_id, slot_id, state=raw_state)
# after
_ALLOWED = {'IMPORTING', 'NODE', 'MIGRATING'}
state = raw_state.upper()
if state == 'STABLE':
r.cluster_setslot_stable(slot_id)
elif state in _ALLOWED:
r.cluster_setslot(node, node_id, slot_id, state=state)
else:
raise ValueError(f'unsupported slot state: {raw_state}') Defensive patterns
Strategy: validation
Validate before calling
_SLOT_STATES = {'IMPORTING', 'NODE', 'MIGRATING', 'STABLE'}
state = str(state).upper()
if state not in _SLOT_STATES:
raise ValueError(f'Unsupported slot state: {state!r}') Type guard
def is_valid_slot_state(state: str) -> bool:
return str(state).upper() in {'IMPORTING', 'NODE', 'MIGRATING', 'STABLE'} Try / catch
from redis.exceptions import RedisError
try:
client.cluster_setslot(target_node, node_id, slot_id, state=state)
except RedisError as e:
if 'Invalid slot state' in str(e):
log.error('Bad slot state %r; allowed: IMPORTING/NODE/MIGRATING/STABLE', state)
raise Prevention
- Keep an allow-list constant of slot states near your reshard code.
- Never source state from unvalidated user/config input.
When it happens
Trigger: Calling cluster_setslot(target_node, node_id, slot_id, state) where state is anything other than the four known strings (case-insensitive) — e.g. 'STABLEE', 'migrate', 'IMPORT', an empty string, None.upper()'d path, or a value sourced from a misconfigured variable.
Common situations: Typos in the state string; passing a server-side synonym that the client does not recognize; data-driven code feeding an unvalidated state from config or a DB; using lowercase 'stable' intentionally but hitting the dedicated-method error is a different (240) path.
Related errors
- For "stable" state please use cluster_setslot_stable
- Subcommand {subcommand_name} not found in command {command_n
- Command {command_name} not found in commands
- Invalid option for CLUSTER FAILOVER command: {option}
- genpass optionally accepts a bits argument, between 0 and 40
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/bc47f76a390fedd6.json.
Report an issue: GitHub.