redis/redis-py · error · DataError

CLIENT KILL type must be one of {client_types!r}

Error message

CLIENT KILL type must be one of {client_types!r}

What it means

Raised by client_kill when the _type argument is not one of the five recognized client types: ('normal', 'master', 'slave', 'replica', 'pubsub'). The check is case-insensitive via str(_type).lower(), so casing is tolerated but the value must match exactly one of those strings. redis-py validates this client-side before sending anything to the server.

Source

Thrown at redis/commands/core.py:778

    ) -> int | Awaitable[int]:
        """
        Disconnects client(s) using a variety of filter options
        :param _id: Kills a client by its unique ID field
        :param _type: Kills a client by type where type is one of 'normal',
        'master', 'slave', 'replica' or 'pubsub'
        :param addr: Kills a client by its 'address:port'
        :param skipme: If True, then the client calling the command
        will not get killed even if it is identified by one of the filter
        options. If skipme is not provided, the server defaults to skipme=True
        :param laddr: Kills a client by its 'local (bind) address:port'
        :param user: Kills a client for a specific user name
        :param maxage: Kills clients that are older than the specified age in seconds
        """
        args = []
        if _type is not None:
            client_types = ("normal", "master", "slave", "replica", "pubsub")
            if str(_type).lower() not in client_types:
                raise DataError(f"CLIENT KILL type must be one of {client_types!r}")
            args.extend((b"TYPE", _type))
        if skipme is not None:
            if not isinstance(skipme, bool):
                raise DataError("CLIENT KILL skipme must be a bool")
            if skipme:
                args.extend((b"SKIPME", b"YES"))
            else:
                args.extend((b"SKIPME", b"NO"))
        if _id is not None:
            args.extend((b"ID", _id))
        if addr is not None:
            args.extend((b"ADDR", addr))
        if laddr is not None:
            args.extend((b"LADDR", laddr))
        if user is not None:
            args.extend((b"USER", user))
        if maxage is not None:
            args.extend((b"MAXAGE", maxage))

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Use one of the exact allowed values: 'normal', 'master', 'slave', 'replica', or 'pubsub' (case-insensitive).
  2. If targeting a pub/sub subscriber connection, use _type='pubsub' not 'subscriber'.
  3. If you need to kill a specific connection instead of by type, use _id, addr, laddr, user, or maxage parameters.

Example fix

# before
r.client_kill(_type='subscriber')
# after
r.client_kill(_type='pubsub')
Defensive patterns

Strategy: validation

Validate before calling

VALID_KILL_TYPES = {'normal', 'master', 'slave', 'replica', 'pubsub'}
if _type is not None and str(_type).lower() not in VALID_KILL_TYPES:
    raise ValueError(f'Invalid client kill type: {_type}')

Type guard

def is_valid_kill_type(t: str) -> bool:
    return isinstance(t, str) and t.lower() in {'normal', 'master', 'slave', 'replica', 'pubsub'}

Prevention

When it happens

Trigger: Calling r.client_kill(_type='worker'), r.client_kill(_type='subscriber'), or any _type value outside the five allowed strings. Passing an integer or object as _type whose str().lower() form isn't in the tuple also triggers it.

Common situations: Developer confuses Redis pub/sub subscriber terminology ('subscriber') with the actual type name ('pubsub'). Copy-pasting a _type value from documentation that uses a synonym. Typing 'replicas' (plural) instead of 'replica'.

Related errors


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