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 provided but is not a non-negative int. MAXLEN requires a non-negative integer count; bools, floats, negatives, or string-encoded numbers are rejected because the library appends str(maxlen) directly into the command and validates type to prevent malformed commands.

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 da03cdc7e8)

Solutions

  1. Pass maxlen as a non-negative int, e.g. maxlen=1000.
  2. Coerce/validate config values with int() and a >= 0 check before calling.
  3. Use 0 only if you intend to trim everything (semantics may differ; prefer minid for that).

Example fix

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

Strategy: type-guard

Validate before calling

def validate_maxlen(maxlen):
    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 integer')
    return True

Type guard

def is_valid_maxlen(m) -> bool:
    return m is None or (isinstance(m, int) and not isinstance(m, bool) and m >= 0)

Prevention

When it happens

Trigger: Calling client.xadd(name, fields, maxlen=-1), maxlen=10.5, maxlen='1000', or maxlen=True.

Common situations: Passing a config value loaded as a string; computing maxlen from a float expression; off-by-one producing a negative; passing a bool by mistake.

Related errors


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