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 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.

Solutions

  1. Pass at least one ID: client.xackdel('mystream', 'mygroup', '1234-0').
  2. Guard dynamic ID lists with an 'if ids:' check before calling xackdel.

Example fix

# before
client.xackdel('mystream', 'mygroup')

# after
client.xackdel('mystream', 'mygroup', '1234-0', '1235-0')
Defensive patterns

Strategy: validation

Validate before calling

ids = list(ids)
if not ids:
    raise ValueError('xackdel requires at least one message ID')
client.xackdel(name, group, *ids)

Try / catch

from redis.exceptions import DataError
try:
    client.xackdel(name, group, *ids)
except DataError as e:
    if 'requires at least one message ID' in str(e):
        pass  # nothing to ack-del; skip the call

Prevention

When it happens

Trigger: Calling client.xackdel('mystream', 'mygroup') with no positional IDs, or unpacking an empty list: client.xackdel('mystream', 'mygroup', *[]).

Common situations: Processing a dynamically-built list of IDs that happens to be empty, or forgetting to append the message IDs after the group name.

Related errors


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

Appendix: 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 6a6b581b48)