redis/redis-py · error · DataError

XADD maxlen must be non-negative integer

Error message

XADD maxlen must be non-negative integer

What it means

Raised by xadd() when maxlen is not an int or is negative. MAXLEN trimming requires a non-negative integer count; negative counts and string values like '1000' are rejected client-side before building the command. It is a DataError.

Solutions

  1. Pass maxlen as a non-negative int (e.g. maxlen=1000).
  2. Coerce config values with int() and clamp to >= 0 before calling xadd.

Example fix

# before
client.xadd('s', {'f': 'v'}, maxlen='1000')

# after
client.xadd('s', {'f': 'v'}, maxlen=1000)
Defensive patterns

Strategy: type-guard

Validate before calling

if maxlen is not None and (not isinstance(maxlen, int) or isinstance(maxlen, bool) or maxlen < 0):
    raise ValueError('maxlen must be a non-negative int')
client.xadd(name, fields, maxlen=maxlen)

Type guard

def is_valid_maxlen(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool) and v >= 0

# usage
if maxlen is not None and not is_valid_maxlen(maxlen):
    raise TypeError('maxlen must be a non-negative integer')

Try / catch

from redis.exceptions import DataError
try:
    client.xadd(name, fields, maxlen=maxlen)
except DataError as e:
    if 'maxlen must be non-negative' in str(e):
        client.xadd(name, fields, maxlen=int(maxlen))

Prevention

When it happens

Trigger: Calling client.xadd('s', fields, maxlen=-5), maxlen='1000' (string), or maxlen=1.5 (float).

Common situations: Reading maxlen from a config file as a string, computing it from an expression that can go negative, or using a float from division.

Related errors


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

Appendix: source

Thrown at redis/commands/core.py:7041

        if ref_policy is not None and ref_policy not in {"KEEPREF", "DELREF", "ACKED"}:
            raise DataError("XADD ref_policy must be one of: KEEPREF, DELREF, ACKED")

        if nomkstream:
            pieces.append(b"NOMKSTREAM")
        if ref_policy is not None:
            pieces.append(ref_policy)
        if idmpauto is not None:
            pieces.extend([b"IDMPAUTO", idmpauto])
        if idmp is not None:
            if not isinstance(idmp, tuple) or len(idmp) != 2:
                raise DataError(
                    "XADD idmp must be a tuple of (producer_id, idempotent_id)"
                )
            pieces.extend([b"IDMP", idmp[0], idmp[1]])
        if maxlen is not None:
            if not isinstance(maxlen, int) or maxlen < 0:
                raise DataError("XADD maxlen must be non-negative integer")
            pieces.append(b"MAXLEN")
            if approximate:
                pieces.append(b"~")
            pieces.append(str(maxlen))
        if minid is not None:
            pieces.append(b"MINID")
            if approximate:
                pieces.append(b"~")
            pieces.append(minid)
        if limit is not None:
            pieces.extend([b"LIMIT", limit])
        pieces.append(id)
        if not isinstance(fields, dict) or len(fields) == 0:
            raise DataError("XADD fields must be a non-empty dict")
        for pair in fields.items():
            pieces.extend(pair)
        return self.execute_command("XADD", name, *pieces)

View on GitHub (pinned to 6a6b581b48)