redis/redis-py · error · DataError
XADD idmp must be a tuple of (producer_id, idempotent_id)
Error message
XADD idmp must be a tuple of (producer_id, idempotent_id)
What it means
Raised by xadd() when the idmp argument is not a 2-element tuple. idmp must be exactly (producer_id, idempotent_id) so the client can emit 'IDMP <producer_id> <idempotent_id>' on the wire; lists, shorter/longer tuples, or wrong types are rejected. It is a DataError.
Solutions
- Pass idmp as a tuple of exactly two elements: (producer_id, idempotent_id), e.g. ('producer-1', b'msg-uuid').
- Ensure the second element is the bytes idempotent_id unique per message.
Example fix
# before
client.xadd('s', {'f': 'v'}, idmp=['p1', b'iid'])
# after
client.xadd('s', {'f': 'v'}, idmp=('p1', b'iid')) Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(idmp, tuple) or len(idmp) != 2:
raise ValueError('idmp must be a 2-tuple (producer_id, idempotent_id)')
client.xadd(name, fields, idmp=idmp) Type guard
from typing import Any
def is_valid_idmp(v: Any) -> bool:
return isinstance(v, tuple) and len(v) == 2
# usage
if not is_valid_idmp(idmp):
raise TypeError('idmp must be (producer_id, idempotent_id)') Try / catch
from redis.exceptions import DataError
try:
client.xadd(name, fields, idmp=idmp)
except DataError as e:
if 'idmp must be a tuple' in str(e):
client.xadd(name, fields, idmp=tuple(idmp)) Prevention
- Construct idmp as a literal tuple: ('producer-1', b'msg-uuid').
- If sourcing from a list, convert with tuple() and assert length 2 before calling.
When it happens
Trigger: Calling client.xadd('s', fields, idmp=['p1', b'iid']) (list not tuple), idmp=('p1',) (length 1), or idmp='p1' (string).
Common situations: Using a list instead of a tuple, omitting the idempotent_id, or passing a pre-flattened value.
Related errors
- IDMPAUTO and IDMP can only be used with id='*'
- Only one of ```idmpauto``` or ```idmp``` may be specified
- XADD fields must be a non-empty dict
- XADD maxlen must be non-negative integer
- 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/518c0b8fc66acd8d.
Report an issue: GitHub.
Appendix: source
Thrown at redis/commands/core.py:7035
if idmpauto is not None and idmp is not None:
raise DataError("Only one of ```idmpauto``` or ```idmp``` may be specified")
if (idmpauto is not None or idmp is not None) and id != "*":
raise DataError("IDMPAUTO and IDMP can only be used with id='*'")
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)View on GitHub (pinned to 6a6b581b48)