{"record":{"id":"d4abebb654b5e398","repo":"redis/redis-py","slug":"xackdel-requires-at-least-one-message-id","errorCode":null,"errorMessage":"XACKDEL requires at least one message ID","messagePattern":"XACKDEL requires at least one message ID","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":6929,"sourceCode":"        groupname: GroupT,\n        *ids: StreamIdT,\n        ref_policy: Literal[\"KEEPREF\", \"DELREF\", \"ACKED\"] = \"KEEPREF\",\n    ) -> Awaitable[int]: ...\n\n    def xackdel(\n        self,\n        name: KeyT,\n        groupname: GroupT,\n        *ids: StreamIdT,\n        ref_policy: Literal[\"KEEPREF\", \"DELREF\", \"ACKED\"] = \"KEEPREF\",\n    ) -> int | Awaitable[int]:\n        \"\"\"\n        Combines the functionality of XACK and XDEL. Acknowledges the specified\n        message IDs in the given consumer group and simultaneously attempts to\n        delete the corresponding entries from the stream.\n        \"\"\"\n        if not ids:\n            raise DataError(\"XACKDEL requires at least one message ID\")\n\n        if ref_policy not in {\"KEEPREF\", \"DELREF\", \"ACKED\"}:\n            raise DataError(\"XACKDEL ref_policy must be one of: KEEPREF, DELREF, ACKED\")\n\n        pieces = [name, groupname, ref_policy, \"IDS\", len(ids)]\n        pieces.extend(ids)\n        return self.execute_command(\"XACKDEL\", *pieces)\n\n    @overload\n    def xadd(\n        self: SyncClientProtocol,\n        name: KeyT,\n        fields: Dict[FieldT, EncodableT],\n        id: StreamIdT = \"*\",\n        maxlen: int | None = None,\n        approximate: bool = True,\n        nomkstream: bool = False,\n        minid: StreamIdT | None = None,","sourceCodeStart":6911,"sourceCodeEnd":6947,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L6911-L6947","documentation":"Raised by xackdel() when no message IDs are passed. XACKDEL combines acknowledge and delete for specific stream entries, so at least one ID is mandatory; calling it with zero IDs is always a programming error. It is a DataError.","triggerScenarios":"Calling client.xackdel('mystream', 'mygroup') with no positional IDs, or unpacking an empty list: client.xackdel('mystream', 'mygroup', *[]).","commonSituations":"Processing a dynamically-built list of IDs that happens to be empty, or forgetting to append the message IDs after the group name.","solutions":["Pass at least one ID: client.xackdel('mystream', 'mygroup', '1234-0').","Guard dynamic ID lists with an 'if ids:' check before calling xackdel."],"exampleFix":"# before\nclient.xackdel('mystream', 'mygroup')\n\n# after\nclient.xackdel('mystream', 'mygroup', '1234-0', '1235-0')","handlingStrategy":"validation","validationCode":"ids = list(ids)\nif not ids:\n    raise ValueError('xackdel requires at least one message ID')\nclient.xackdel(name, group, *ids)","typeGuard":null,"tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    client.xackdel(name, group, *ids)\nexcept DataError as e:\n    if 'requires at least one message ID' in str(e):\n        pass  # nothing to ack-del; skip the call","preventionTips":["Guard dynamically-built ID lists with 'if ids:' before calling xackdel.","Log when the ID list is empty so empty batches are visible, not silent."],"tags":["streams","xackdel","validation","required-argument"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}