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
- Pass at least one ID: client.xackdel('mystream', 'mygroup', '1234-0').
- 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
- Guard dynamically-built ID lists with 'if ids:' before calling xackdel.
- Log when the ID list is empty so empty batches are visible, not silent.
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
- XACKDEL ref_policy must be one of: KEEPREF, DELREF, ACKED
- XADD fields must be a non-empty dict
- XCFGSET requires at least one of idmp_duration or…
- IDMPAUTO and IDMP can only be used with id='*'
- Only one of ```idmpauto``` or ```idmp``` may be specified
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)