redis/redis-py · error · DataError

Invalid input of type: '{typename}'. Convert to a bytes, str

Error message

Invalid input of type: '{typename}'. Convert to a bytes, string, int or float first.

What it means

Raised by Encoder.encode() for any value that is not bytes/bytearray/memoryview, bool, int, float, or str. The typename in the message is type(value).__name__, so the message tells you exactly what was passed (e.g. 'NoneType', 'list', 'dict', 'Decimal', 'datetime'). DataError is a RedisError subclass.

Source

Thrown at redis/_parsers/encoders.py:29

        self.encoding_errors = encoding_errors
        self.decode_responses = decode_responses

    def encode(self, value):
        "Return a bytestring or bytes-like representation of the value"
        if isinstance(value, (bytes, bytearray, memoryview)):
            return value
        elif isinstance(value, bool):
            # special case bool since it is a subclass of int
            raise DataError(
                "Invalid input of type: 'bool'. Convert to a "
                "bytes, string, int or float first."
            )
        elif isinstance(value, (int, float)):
            value = repr(value).encode()
        elif not isinstance(value, str):
            # a value we don't know how to deal with. throw an error
            typename = type(value).__name__
            raise DataError(
                f"Invalid input of type: '{typename}'. "
                f"Convert to a bytes, string, int or float first."
            )
        if isinstance(value, str):
            value = value.encode(self.encoding, self.encoding_errors)
        return value

    def decode(self, value, force=False):
        "Return a unicode string from the bytes-like representation"
        if self.decode_responses or force:
            if isinstance(value, memoryview):
                value = value.tobytes()
            if isinstance(value, bytes):
                value = value.decode(self.encoding, self.encoding_errors)
        return value

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Serialize structured objects to bytes/str: json.dumps(value).encode().
  2. Flatten collections: r.lpush('k', *items) instead of r.lpush('k', items).
  3. Coerce numerics: int()/float() for Decimal/numpy scalars before passing.
  4. Handle None explicitly: skip the call, or store a sentinel like b''.

Example fix

// before
r.set("doc", {"a": 1})               # DataError: dict
r.lpush("list", [1, 2, 3])         # DataError: list

// after
import json
r.set("doc", json.dumps({"a": 1}))
r.lpush("list", *[1, 2, 3])
Defensive patterns

Strategy: validation

Validate before calling

# Whitelist scalar types before sending
def coerce_for_redis(v):
    if isinstance(v, bool) or not isinstance(v, (bytes, bytearray, memoryview, int, float, str)):
        raise TypeError(f"unsupported type {type(v).__name__}; serialize first")
    return v

Type guard

def is_redis_scalar(v) -> bool:
    return isinstance(v, (bytes, bytearray, memoryview, int, float, str)) and not isinstance(v, bool)

Try / catch

try:
    r.set("k", value)
except redis.exceptions.DataError as e:
    if "Invalid input of type" in str(e):
        import json
        r.set("k", json.dumps(value))  # serialize structured data

Prevention

When it happens

Trigger: Passing None, list, dict, tuple, Decimal, datetime, UUID, dataclass, Pydantic model, numpy scalar, pandas NA, or any custom object as a command value or argument. Common: r.set('k', None), r.lpush('list', [1,2,3]) instead of *list, r.hset('h', mapping={'a': Decimal('1.2')}).

Common situations: Forgetting to serialize structured data (use json.dumps / pickle / msgpack); passing None instead of an empty bytestring; third-party numeric types (Decimal, numpy) that are not int/float; nested collections passed where a flat value is expected.

Related errors


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