redis/redis-py · error · DataError
client_id must be a list
Error message
client_id must be a list
What it means
Raised by client_list() (redis/commands/core.py:860) when the client_id argument is not a Python list. The library does isinstance(client_id, list), so a single int, a tuple, a set, or a numpy array are all rejected even if they contain valid ids. This is a redis.exceptions.DataError raised before the command is sent.
Solutions
- Wrap a single id in a list: r.client_list(client_id=[42])
- Convert other iterables: r.client_list(client_id=list(ids))
- If using numpy/pandas, call .tolist() first
Example fix
# before r.client_list(client_id=r.client_id()) # after r.client_list(client_id=[r.client_id()])
Defensive patterns
Strategy: type-guard
Validate before calling
if client_id is not None and not isinstance(client_id, list):
client_id = list(client_id)
r.client_list(client_id=client_id or []) Type guard
from typing import List, TypeGuard
def is_id_list(v) -> TypeGuard[List[int]]:
return isinstance(v, list) and all(isinstance(x, int) for x in v) Try / catch
from redis.exceptions import DataError
try:
r.client_list(client_id=ids)
except DataError as e:
if "client_id must be a list" in str(e):
r.client_list(client_id=list(ids))
else:
raise Prevention
- Always pass client_id as a Python list, even for a single id.
- Normalize tuples/sets/generators with list(...) at the boundary.
- If ids originate from numpy/pandas, call .tolist().
When it happens
Trigger: Calling r.client_list(client_id=42) (single id instead of list), r.client_list(client_id=(1,2)) (tuple), or r.client_list(client_id={1,2}) (set). The default [] does not trigger it.
Common situations: Passing a single client id obtained from client_id() directly; or passing a tuple/set from another data structure; or an ORM/pandas Series that is not a plain list.
Related errors
- CLIENT KILL skipme must be a bool
- CLIENT PAUSE timeout must be an integer
- CLIENT KILL ... ... must specify at least one filter
- CLIENT LIST _type must be one of
- CLIENT REPLY must be one of
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/6a9fd3acaf114748.
Report an issue: GitHub.
Appendix: source
Thrown at redis/commands/core.py:860
"""
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[
bytes | str | None
]:
"""
Returns the current connection nameView on GitHub (pinned to 6a6b581b48)