{"id":"518c0b8fc66acd8d","repo":"redis/redis-py","slug":"xadd-idmp-must-be-a-tuple-of-producer-id-idempot","errorCode":null,"errorMessage":"XADD idmp must be a tuple of (producer_id, idempotent_id)","messagePattern":"XADD idmp must be a tuple of \\(producer_id, idempotent_id\\)","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":7035,"sourceCode":"\n        if idmpauto is not None and idmp is not None:\n            raise DataError(\"Only one of ```idmpauto``` or ```idmp``` may be specified\")\n\n        if (idmpauto is not None or idmp is not None) and id != \"*\":\n            raise DataError(\"IDMPAUTO and IDMP can only be used with id='*'\")\n\n        if ref_policy is not None and ref_policy not in {\"KEEPREF\", \"DELREF\", \"ACKED\"}:\n            raise DataError(\"XADD ref_policy must be one of: KEEPREF, DELREF, ACKED\")\n\n        if nomkstream:\n            pieces.append(b\"NOMKSTREAM\")\n        if ref_policy is not None:\n            pieces.append(ref_policy)\n        if idmpauto is not None:\n            pieces.extend([b\"IDMPAUTO\", idmpauto])\n        if idmp is not None:\n            if not isinstance(idmp, tuple) or len(idmp) != 2:\n                raise DataError(\n                    \"XADD idmp must be a tuple of (producer_id, idempotent_id)\"\n                )\n            pieces.extend([b\"IDMP\", idmp[0], idmp[1]])\n        if maxlen is not None:\n            if not isinstance(maxlen, int) or maxlen < 0:\n                raise DataError(\"XADD maxlen must be non-negative integer\")\n            pieces.append(b\"MAXLEN\")\n            if approximate:\n                pieces.append(b\"~\")\n            pieces.append(str(maxlen))\n        if minid is not None:\n            pieces.append(b\"MINID\")\n            if approximate:\n                pieces.append(b\"~\")\n            pieces.append(minid)\n        if limit is not None:\n            pieces.extend([b\"LIMIT\", limit])\n        pieces.append(id)","sourceCodeStart":7017,"sourceCodeEnd":7053,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/core.py#L7017-L7053","documentation":"Raised by xadd() when idmp is provided but is not a 2-element tuple. idmp must be a (producer_id, idempotent_id) pair where producer_id is a str and idempotent_id is bytes; the library destructures idmp[0] and idmp[1] when building the IDMP command clause.","triggerScenarios":"Calling client.xadd(name, fields, id='*', idmp='prod-1'), idmp=['p1', b'x'] (list not tuple), or idmp=('p1',) (single element).","commonSituations":"Passing a list instead of a tuple; passing only a producer ID; passing a flat string; misreading the type hint.","solutions":["Pass idmp as a 2-tuple: idmp=('producer-1', b'idempotent-id').","Ensure the second element is bytes (the idempotent ID).","If you only have a producer ID, use idmpauto instead."],"exampleFix":"# before\nawait r.xadd('s', {'f':'v'}, id='*', idmp='prod-1')\n# after\nawait r.xadd('s', {'f':'v'}, id='*', idmp=('prod-1', b'abc123'))","handlingStrategy":"type-guard","validationCode":"def validate_idmp(idmp):\n    if idmp is not None and (not isinstance(idmp, tuple) or len(idmp) != 2):\n        raise ValueError('idmp must be a (producer_id, idempotent_id) tuple')\n    return True","typeGuard":"def is_valid_idmp(idmp) -> bool:\n    return idmp is None or (isinstance(idmp, tuple) and len(idmp) == 2)","tryCatchPattern":null,"preventionTips":["Pass idmp as a 2-tuple: ('producer-id', b'idempotent-id').","Use idmpauto if you only have a producer ID.","Do not pass a list, string, or single value for idmp."],"tags":["stream","xadd","idempotency","validation","dataerror"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}