{"id":"ff66b2e2c8463176","repo":"redis/redis-py","slug":"xadd-fields-must-be-a-non-empty-dict","errorCode":null,"errorMessage":"XADD fields must be a non-empty dict","messagePattern":"XADD fields must be a non-empty dict","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":7055,"sourceCode":"                )\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)\n        if not isinstance(fields, dict) or len(fields) == 0:\n            raise DataError(\"XADD fields must be a non-empty dict\")\n        for pair in fields.items():\n            pieces.extend(pair)\n        return self.execute_command(\"XADD\", name, *pieces)\n\n    @overload\n    def xcfgset(\n        self: SyncClientProtocol,\n        name: KeyT,\n        idmp_duration: int | None = None,\n        idmp_maxsize: int | None = None,\n    ) -> bytes | str: ...\n\n    @overload\n    def xcfgset(\n        self: AsyncClientProtocol,\n        name: KeyT,\n        idmp_duration: int | None = None,\n        idmp_maxsize: int | None = None,","sourceCodeStart":7037,"sourceCodeEnd":7073,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/core.py#L7037-L7073","documentation":"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.","triggerScenarios":"Calling client.xadd(name, {}), client.xadd(name, None), or client.xadd(name, [('f','v')]) (list instead of dict).","commonSituations":"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.","solutions":["Pass a non-empty dict, e.g. xadd('s', {'field': 'value'}).","Guard callers to skip XADD when the fields dict is empty.","Ensure the value is a dict (not a list of tuples or None) before calling."],"exampleFix":"# before\nawait r.xadd('s', {})\n# after\nawait r.xadd('s', {'field': 'value'})","handlingStrategy":"type-guard","validationCode":"def validate_fields(fields):\n    if not isinstance(fields, dict) or len(fields) == 0:\n        raise ValueError('fields must be a non-empty dict')\n    return True","typeGuard":"def is_valid_fields(f) -> bool:\n    return isinstance(f, dict) and len(f) > 0","tryCatchPattern":null,"preventionTips":["Always pass a non-empty dict for fields.","Skip XADD when the computed fields dict is empty rather than calling it.","Ensure the value is a dict, not a list of tuples or None."],"tags":["stream","xadd","validation","dataerror"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}