{"record":{"id":"2e146882fc7f0117","repo":"redis/redis-py","slug":"xnack-requires-at-least-one-message-id","errorCode":null,"errorMessage":"XNACK requires at least one message ID","messagePattern":"XNACK requires at least one message ID","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":7680,"sourceCode":"            name: name of the stream.\n            groupname: name of the consumer group.\n            mode: the nacking mode. One of SILENT, FAIL, or FATAL.\n                SILENT: consumer shutting down; decrements delivery counter.\n                FAIL: consumer unable to process; delivery counter unchanged.\n                FATAL: invalid/malicious message; delivery counter set to max.\n            *ids: one or more message IDs to NACK.\n            retrycount: optional integer >= 0. Overrides the mode's implicit\n                delivery counter adjustment with an exact value.\n            force: if True, creates a new unowned PEL entry for any ID not\n                already in the group's PEL.\n\n        Returns:\n            The number of messages successfully NACKed.\n\n        For more information, see https://redis.io/commands/xnack\n        \"\"\"\n        if not ids:\n            raise DataError(\"XNACK requires at least one message ID\")\n\n        if mode not in {\"SILENT\", \"FAIL\", \"FATAL\"}:\n            raise DataError(\"XNACK mode must be one of: SILENT, FAIL, FATAL\")\n\n        pieces: list = [name, groupname, mode, \"IDS\", len(ids)]\n        pieces.extend(ids)\n\n        if retrycount is not None:\n            if retrycount < 0:\n                raise DataError(\"XNACK retrycount must be >= 0\")\n            pieces.extend([b\"RETRYCOUNT\", retrycount])\n\n        if force:\n            pieces.append(b\"FORCE\")\n\n        return self.execute_command(\"XNACK\", *pieces)\n\n    @overload","sourceCodeStart":7662,"sourceCodeEnd":7698,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L7662-L7698","documentation":"Raised by Redis.xnack() when no message IDs are supplied via *ids. xnack negatively acknowledges one or more messages; at least one ID is mandatory.","triggerScenarios":"Calling r.xnack('mystream', 'grp', 'FAIL') with no IDs, or r.xnack('mystream', 'grp', 'FAIL', *bad_ids) where bad_ids unpacks to nothing.","commonSituations":"Empty dead-letter list, or unpacking a filtered set that matched nothing.","solutions":["Supply at least one ID, e.g. r.xnack('mystream', 'grp', 'FAIL', '1-0').","Skip the call when the ID list is empty."],"exampleFix":"# before\nr.xnack('mystream', 'grp', 'FAIL', *dead)  # dead == []\n\n# after\nif dead:\n    r.xnack('mystream', 'grp', 'FAIL', *dead)","handlingStrategy":"validation","validationCode":"if not ids:\n    raise ValueError('xnack requires at least one id')","typeGuard":"lambda *ids: len(ids) > 0","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    r.xnack('mystream', 'grp', mode, *ids)\nexcept DataError as e:\n    if ids:\n        raise\n    # nothing to nack","preventionTips":["Short-circuit empty ID lists; nack-ing nothing is never useful."],"tags":["stream","xnack","validation","argument-shape"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}