redis/redis-py · error · DataError
CLIENT LIST _type must be one of
Error message
CLIENT LIST _type must be one of {client_types!r} What it means
Raised by client_list() (redis/commands/core.py:856) when _type is not one of ('normal','master','replica','pubsub'). The check is case-insensitive via str(_type).lower(), so 'Normal' or 'REPLICA' pass. Note this set is SMALLER than client_kill's type set: client_list does NOT accept 'slave' (use 'replica'). This is a redis.exceptions.DataError raised before the command is sent.
Solutions
- Use one of the accepted values: r.client_list(_type="normal"), _type="master", _type="replica", or _type="pubsub"
- Replace legacy 'slave' with 'replica' for client_list
- Drop the _type argument to list every connected client regardless of type
Example fix
# before r.client_list(_type="slave") # after r.client_list(_type="replica")
Defensive patterns
Strategy: validation
Validate before calling
CLIENT_LIST_TYPES = {"normal", "master", "replica", "pubsub"}
if _type is not None and _type.lower() not in CLIENT_LIST_TYPES:
raise ValueError(f"_type must be one of {CLIENT_LIST_TYPES}")
r.client_list(_type=_type) Type guard
from typing import Literal
ClientListType = Literal["normal", "master", "replica", "pubsub"]
def is_client_list_type(v: str) -> TypeGuard[ClientListType]:
return v.lower() in {"normal", "master", "replica", "pubsub"} Try / catch
from redis.exceptions import DataError
try:
r.client_list(_type=t)
except DataError as e:
if "_type must be one of" in str(e):
r.client_list() # fall back to unfiltered list
else:
raise Prevention
- Remember client_list does NOT accept 'slave'; use 'replica'.
- Normalize _type to lowercase before calling (the check is case-insensitive).
- Keep an allowlist constant near your call site rather than hardcoding strings.
When it happens
Trigger: Calling r.client_list(_type="slave") (legacy spelling not allowed here), r.client_list(_type="clients"), r.client_list(_type="all"), or any unrecognized string. _type=None (default) is fine.
Common situations: Reusing the 'slave' spelling that works elsewhere in Redis, or inventing a type name like 'all'/'clients'. Also when copy-pasting from client_kill examples that include 'slave'.
Related errors
- client_id must be a list
- CLIENT KILL ... ... must specify at least one filter
- CLIENT KILL skipme must be a bool
- CLIENT PAUSE timeout must be an integer
- CLIENT REPLY must be one of
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/3c1303db54e9934a.
Report an issue: GitHub.
Appendix: source
Thrown at redis/commands/core.py:856
def client_list(
self, _type: str | None = None, client_id: List[EncodableT] = [], **kwargs
) -> list[dict[str, str]] | Awaitable[list[dict[str, str]]]:
"""
Returns a list of currently connected clients.
If type of client specified, only that type will be returned.
:param _type: optional. one of the client types (normal, master,
replica, pubsub)
:param client_id: optional. a list of client ids
For more information, see https://redis.io/commands/client-list
"""
args = []
if _type is not None:
client_types = ("normal", "master", "replica", "pubsub")
if str(_type).lower() not in client_types:
raise DataError(f"CLIENT LIST _type must be one of {client_types!r}")
args.append(b"TYPE")
args.append(_type)
if not isinstance(client_id, list):
raise DataError("client_id must be a list")
if client_id:
args.append(b"ID")
args += client_id
return self.execute_command("CLIENT LIST", *args, **kwargs)
@overload
def client_getname(self: SyncClientProtocol, **kwargs) -> bytes | str | None: ...
@overload
def client_getname(
self: AsyncClientProtocol, **kwargs
) -> Awaitable[bytes | str | None]: ...
def client_getname(self, **kwargs) -> (bytes | str | None) | Awaitable[View on GitHub (pinned to 6a6b581b48)