redis/redis-py · error · DataError

XNACK requires at least one message ID

Error message

XNACK requires at least one message ID

What it means

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.

Solutions

  1. Supply at least one ID, e.g. r.xnack('mystream', 'grp', 'FAIL', '1-0').
  2. Skip the call when the ID list is empty.

Example fix

# before
r.xnack('mystream', 'grp', 'FAIL', *dead)  # dead == []

# after
if dead:
    r.xnack('mystream', 'grp', 'FAIL', *dead)
Defensive patterns

Strategy: validation

Validate before calling

if not ids:
    raise ValueError('xnack requires at least one id')

Type guard

lambda *ids: len(ids) > 0

Try / catch

from redis.exceptions import DataError
try:
    r.xnack('mystream', 'grp', mode, *ids)
except DataError as e:
    if ids:
        raise
    # nothing to nack

Prevention

When it happens

Trigger: Calling r.xnack('mystream', 'grp', 'FAIL') with no IDs, or r.xnack('mystream', 'grp', 'FAIL', *bad_ids) where bad_ids unpacks to nothing.

Common situations: Empty dead-letter list, or unpacking a filtered set that matched nothing.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/2e146882fc7f0117. Report an issue: GitHub.

Appendix: source

Thrown at redis/commands/core.py:7680

            name: name of the stream.
            groupname: name of the consumer group.
            mode: the nacking mode. One of SILENT, FAIL, or FATAL.
                SILENT: consumer shutting down; decrements delivery counter.
                FAIL: consumer unable to process; delivery counter unchanged.
                FATAL: invalid/malicious message; delivery counter set to max.
            *ids: one or more message IDs to NACK.
            retrycount: optional integer >= 0. Overrides the mode's implicit
                delivery counter adjustment with an exact value.
            force: if True, creates a new unowned PEL entry for any ID not
                already in the group's PEL.

        Returns:
            The number of messages successfully NACKed.

        For more information, see https://redis.io/commands/xnack
        """
        if not ids:
            raise DataError("XNACK requires at least one message ID")

        if mode not in {"SILENT", "FAIL", "FATAL"}:
            raise DataError("XNACK mode must be one of: SILENT, FAIL, FATAL")

        pieces: list = [name, groupname, mode, "IDS", len(ids)]
        pieces.extend(ids)

        if retrycount is not None:
            if retrycount < 0:
                raise DataError("XNACK retrycount must be >= 0")
            pieces.extend([b"RETRYCOUNT", retrycount])

        if force:
            pieces.append(b"FORCE")

        return self.execute_command("XNACK", *pieces)

    @overload

View on GitHub (pinned to 6a6b581b48)