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 xnack() when no message id is supplied. XNACK requires at least one id to negatively acknowledge. Check at core.py:7679: `if not ids`.

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 da03cdc7e8)

Solutions

  1. Pass at least one id after mode: r.xnack(name, group, mode, id1, ...).
  2. Guard: if ids: r.xnack(name, group, mode, *ids).

Example fix

# before
r.xnack('s','g','FAIL')
# after
if bad_ids:
    r.xnack('s','g','FAIL', *bad_ids)
Defensive patterns

Strategy: validation

Validate before calling

if not ids:
    raise ValueError('xnack needs >= 1 id')
r.xnack(name, group, mode, *ids, retrycount=retrycount, force=force)

Try / catch

from redis.exceptions import DataError
try:
    r.xnack(name, group, mode, *ids)
except DataError:
    pass  # nothing to nack

Prevention

When it happens

Trigger: r.xnack('s','g','FAIL') with no ids after mode, or r.xnack('s','g','SILENT').

Common situations: Calling XNACK on an empty ack-list from a batch processor; spreading an empty ids tuple; forgetting that mode is a positional arg followed by *ids.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/2e146882fc7f0117.json. Report an issue: GitHub.