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 when the client_id argument is not a Python list. The default is an empty list [] and the method appends b'ID' then spreads the list entries into args, so a scalar or tuple would break the protocol encoding.

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 name

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Wrap single IDs in a list: client_list(client_id=[my_id]).
  2. Convert tuples/other sequences: client_list(client_id=list(my_ids)).
  3. Ensure the value is a list before passing, especially when sourced dynamically.

Example fix

# before
r.client_list(client_id=current_id)
# after
r.client_list(client_id=[current_id])
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(client_id, list):
    client_id = [client_id] if client_id is not None else []
# now safe

Type guard

def is_client_id_list(v) -> bool:
    return isinstance(v, list)

Prevention

When it happens

Trigger: Calling r.client_list(client_id=42) with a single int. Passing a tuple client_id=(1,2,3) or a generator/iterator. Passing a numpy array or other non-list sequence.

Common situations: Developer wraps a single ID without brackets: client_id=some_id instead of client_id=[some_id]. Data loaded from a DB cursor as a tuple. Passing the result of client_id() (a scalar) directly.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/6a9fd3acaf114748.json. Report an issue: GitHub.