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 in the stream entry; passing a list, None, or {} is invalid. It is a DataError.
Solutions
- Pass a non-empty dict of field/value pairs, e.g. {'field1': 'value1'}.
- If the dict may be empty at runtime, guard with 'if fields:' before calling xadd.
Example fix
# before
client.xadd('mystream', {})
# after
client.xadd('mystream', {'field1': 'value1'}) Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(fields, dict) or not fields:
raise ValueError('fields must be a non-empty dict')
client.xadd(name, fields) Type guard
def is_valid_fields(v) -> bool:
return isinstance(v, dict) and len(v) > 0
# usage
if not is_valid_fields(fields):
raise TypeError('fields must be a non-empty dict') Try / catch
from redis.exceptions import DataError
try:
client.xadd(name, fields)
except DataError as e:
if 'fields must be a non-empty dict' in str(e):
fields = {'placeholder': '1'}
client.xadd(name, fields) Prevention
- Guard dynamically-built field dicts with 'if fields:' before calling xadd.
- Convert list-of-pairs to dict with dict(pairs) and ensure it is non-empty.
When it happens
Trigger: Calling client.xadd('mystream', {}), client.xadd('mystream', [('f', 'v')]) (list of pairs), or client.xadd('mystream', None).
Common situations: Building fields from a query/result that produced no rows, or passing a list of tuples instead of a dict.
Related errors
- XADD idmp must be a tuple of (producer_id, idempotent_id)
- XADD maxlen must be non-negative integer
- IDMPAUTO and IDMP can only be used with id='*'
- Only one of ```idmpauto``` or ```idmp``` may be specified
- Only one of ```maxlen``` or ```minid``` may be specified
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/ff66b2e2c8463176.
Report an issue: GitHub.
Appendix: 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 6a6b581b48)