redis/redis-py · error · DataError

XADD fields must be a non-empty dict

Error message

XADD fields must be a non-empty dict

What it means

Raised by xadd() when fields is not a dict or is an empty dict. XADD requires at least one field/value pair per entry (Redis stream entries cannot be empty), so the client validates that fields is a non-empty mapping before iterating fields.items() to build the command.

Source

Thrown at redis/commands/core.py:7055

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

    @overload
    def xcfgset(
        self: SyncClientProtocol,
        name: KeyT,
        idmp_duration: int | None = None,
        idmp_maxsize: int | None = None,
    ) -> bytes | str: ...

    @overload
    def xcfgset(
        self: AsyncClientProtocol,
        name: KeyT,
        idmp_duration: int | None = None,
        idmp_maxsize: int | None = None,

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Pass a non-empty dict, e.g. xadd('s', {'field': 'value'}).
  2. Guard callers to skip XADD when the fields dict is empty.
  3. Ensure the value is a dict (not a list of tuples or None) before calling.

Example fix

# before
await r.xadd('s', {})
# after
await r.xadd('s', {'field': 'value'})
Defensive patterns

Strategy: type-guard

Validate before calling

def validate_fields(fields):
    if not isinstance(fields, dict) or len(fields) == 0:
        raise ValueError('fields must be a non-empty dict')
    return True

Type guard

def is_valid_fields(f) -> bool:
    return isinstance(f, dict) and len(f) > 0

Prevention

When it happens

Trigger: Calling client.xadd(name, {}), client.xadd(name, None), or client.xadd(name, [('f','v')]) (list instead of dict).

Common situations: Building the fields dict dynamically and emitting an entry when the dict is empty; passing None from an optional source; passing a list of pairs instead of a dict.

Related errors


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