redis/redis-py · error · DataError

XACKDEL requires at least one message ID

Error message

XACKDEL requires at least one message ID

What it means

Raised by xackdel() when no message IDs are passed. XACKDEL combines acknowledgement and deletion for specific stream entries, so at least one ID must be supplied via the variadic *ids parameter; an empty ID list would be a no-op and is rejected up front.

Source

Thrown at redis/commands/core.py:6929

        groupname: GroupT,
        *ids: StreamIdT,
        ref_policy: Literal["KEEPREF", "DELREF", "ACKED"] = "KEEPREF",
    ) -> Awaitable[int]: ...

    def xackdel(
        self,
        name: KeyT,
        groupname: GroupT,
        *ids: StreamIdT,
        ref_policy: Literal["KEEPREF", "DELREF", "ACKED"] = "KEEPREF",
    ) -> int | Awaitable[int]:
        """
        Combines the functionality of XACK and XDEL. Acknowledges the specified
        message IDs in the given consumer group and simultaneously attempts to
        delete the corresponding entries from the stream.
        """
        if not ids:
            raise DataError("XACKDEL requires at least one message ID")

        if ref_policy not in {"KEEPREF", "DELREF", "ACKED"}:
            raise DataError("XACKDEL ref_policy must be one of: KEEPREF, DELREF, ACKED")

        pieces = [name, groupname, ref_policy, "IDS", len(ids)]
        pieces.extend(ids)
        return self.execute_command("XACKDEL", *pieces)

    @overload
    def xadd(
        self: SyncClientProtocol,
        name: KeyT,
        fields: Dict[FieldT, EncodableT],
        id: StreamIdT = "*",
        maxlen: int | None = None,
        approximate: bool = True,
        nomkstream: bool = False,
        minid: StreamIdT | None = None,

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Pass at least one message ID: client.xackdel(name, groupname, '1234-0').
  2. Guard the caller so XACKDEL is skipped when the ID list is empty.
  3. Validate len(ids) > 0 before invoking the command.

Example fix

# before
await r.xackdel('mystream', 'grp')
# after
await r.xackdel('mystream', 'grp', '1234-0', '1235-0')
Defensive patterns

Strategy: validation

Validate before calling

def validate_xackdel_ids(ids):
    if not ids:
        raise ValueError('XACKDEL requires at least one message ID')
    return True

Prevention

When it happens

Trigger: Calling client.xackdel(name, groupname) with no positional IDs, e.g. spreading an empty list: client.xackdel(name, groupname, *[]).

Common situations: Processing a batch that happened to be empty; spreading a list of pending IDs without guarding for the empty case.

Related errors


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