redis/redis-py · error · DataError

<dynamic TypeError message from hiredis.pack_command>

Error message

<dynamic TypeError message from hiredis.pack_command>

What it means

Raised by HiredisRespSerializer.pack when hiredis.pack_command raises a TypeError on a command argument that cannot be encoded to bytes. The library catches the TypeError and re-raises it as a redis.exceptions.DataError, preserving the original TypeError message (so the exact text is dynamic). Typical causes: passing None, a dict, a list, or another non-encodable object as a command argument when the hiredis protocol serializer is active.

Source

Thrown at redis/connection.py:142

class HiredisRespSerializer:
    def pack(self, *args: List):
        """Pack a series of arguments into the Redis protocol"""
        output = []

        if isinstance(args[0], str):
            args = tuple(args[0].encode().split()) + args[1:]
        elif b" " in args[0]:
            args = tuple(args[0].split()) + args[1:]
        args = tuple(
            bytes(arg) if isinstance(arg, (bytearray, memoryview)) else arg
            for arg in args
        )
        try:
            output.append(hiredis.pack_command(args))
        except TypeError:
            _, value, traceback = sys.exc_info()
            raise DataError(value).with_traceback(traceback)

        return output


class PythonRespSerializer:
    def __init__(self, buffer_cutoff, encode) -> None:
        self._buffer_cutoff = buffer_cutoff
        self.encode = encode

    def pack(self, *args):
        """Pack a series of arguments into the Redis protocol"""
        output = []
        # the client might have included 1 or more literal arguments in
        # the command name, e.g., 'CONFIG GET'. The Redis server expects these
        # arguments to be sent separately, so split the first argument
        # manually. These arguments should be bytestrings so that they are
        # not encoded.
        if isinstance(args[0], str):

View on GitHub (pinned to 6a6b581b48)

Solutions

  1. Inspect the exact TypeError text in the raised DataError to find which argument failed to encode.
  2. Convert the offending argument to str/bytes/int before sending (e.g., str(value), or skip None-valued fields).
  3. Strip None values from command payloads (common with HSET/MSET over partial records).
  4. If you must debug, reproduce with the pure-Python parser (protocol without hiredis) to see encoding details, then fix the value.

Example fix

// before
client.hset('user:1', mapping={'name':'alice','email':None})
// after
mapping = {'name':'alice'}
if email is not None:
    mapping['email'] = email
client.hset('user:1', mapping=mapping)
Defensive patterns

Strategy: validation

Validate before calling

def encode_safe(value):
    if value is None:
        raise ValueError('None cannot be sent as a command argument')
    return value
# strip None values before sending
mapping = {k: v for k, v in record.items() if v is not None}
client.hset('user:1', mapping=mapping)

Type guard

def is_encodable(value) -> bool:
    return isinstance(value, (str, bytes, bytearray, int, float))

Try / catch

from redis.exceptions import DataError
try:
    client.execute_command(*args)
except DataError as e:
    # inspect e.args[0] for the underlying TypeError message
    args = [a if a is not None else '' for a in args]
    client.execute_command(*args)

Prevention

When it happens

Trigger: Any client.execute_command / convenience call where an argument is None, a dict, a nested list, or another Python object that is neither str/bytes/bytearray/int. Happens only when the hiredis parser/serializer is installed (hiredis >= 3.2.0); the pure-Python serializer has different encoding behavior and may not raise identically.

Common situations: Passing None where a value is required (e.g., hset with a None field value). Sending a dict or nested structure the library does not auto-serialize. A field that is sometimes None due to upstream data. Version change enabling hiredis where previously the pure-Python path tolerated the value.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/502935adbb272b09. Report an issue: GitHub.