{"record":{"id":"502935adbb272b09","repo":"redis/redis-py","slug":"dynamic-typeerror-message-from-hiredis-pack-comma","errorCode":null,"errorMessage":"<dynamic TypeError message from hiredis.pack_command>","messagePattern":"<dynamic TypeError message from hiredis\\.pack_command>","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/connection.py","lineNumber":142,"sourceCode":"\nclass HiredisRespSerializer:\n    def pack(self, *args: List):\n        \"\"\"Pack a series of arguments into the Redis protocol\"\"\"\n        output = []\n\n        if isinstance(args[0], str):\n            args = tuple(args[0].encode().split()) + args[1:]\n        elif b\" \" in args[0]:\n            args = tuple(args[0].split()) + args[1:]\n        args = tuple(\n            bytes(arg) if isinstance(arg, (bytearray, memoryview)) else arg\n            for arg in args\n        )\n        try:\n            output.append(hiredis.pack_command(args))\n        except TypeError:\n            _, value, traceback = sys.exc_info()\n            raise DataError(value).with_traceback(traceback)\n\n        return output\n\n\nclass PythonRespSerializer:\n    def __init__(self, buffer_cutoff, encode) -> None:\n        self._buffer_cutoff = buffer_cutoff\n        self.encode = encode\n\n    def pack(self, *args):\n        \"\"\"Pack a series of arguments into the Redis protocol\"\"\"\n        output = []\n        # the client might have included 1 or more literal arguments in\n        # the command name, e.g., 'CONFIG GET'. The Redis server expects these\n        # arguments to be sent separately, so split the first argument\n        # manually. These arguments should be bytestrings so that they are\n        # not encoded.\n        if isinstance(args[0], str):","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/connection.py#L124-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the exact TypeError text in the raised DataError to find which argument failed to encode.","Convert the offending argument to str/bytes/int before sending (e.g., str(value), or skip None-valued fields).","Strip None values from command payloads (common with HSET/MSET over partial records).","If you must debug, reproduce with the pure-Python parser (protocol without hiredis) to see encoding details, then fix the value."],"exampleFix":"// before\nclient.hset('user:1', mapping={'name':'alice','email':None})\n// after\nmapping = {'name':'alice'}\nif email is not None:\n    mapping['email'] = email\nclient.hset('user:1', mapping=mapping)","handlingStrategy":"validation","validationCode":"def encode_safe(value):\n    if value is None:\n        raise ValueError('None cannot be sent as a command argument')\n    return value\n# strip None values before sending\nmapping = {k: v for k, v in record.items() if v is not None}\nclient.hset('user:1', mapping=mapping)","typeGuard":"def is_encodable(value) -> bool:\n    return isinstance(value, (str, bytes, bytearray, int, float))","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    client.execute_command(*args)\nexcept DataError as e:\n    # inspect e.args[0] for the underlying TypeError message\n    args = [a if a is not None else '' for a in args]\n    client.execute_command(*args)","preventionTips":["Strip None from mappings/lists before sending commands.","Coerce non-primitive types (dict/list) to JSON or appropriate encodings explicitly.","Watch for this specifically when hiredis is installed; test with realistic values."],"tags":["connection","hiredis","encoding","serialization"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}