redis/redis-py · error · DataError

XDELEX ref_policy must be one of: KEEPREF, DELREF, ACKED

Error message

XDELEX ref_policy must be one of: KEEPREF, DELREF, ACKED

What it means

Raised by xdelex() when ref_policy is not one of KEEPREF, DELREF, ACKED. Case-SENSITIVE membership test at core.py:7377. Default is KEEPREF.

Source

Thrown at redis/commands/core.py:7378

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

    def xdelex(
        self,
        name: KeyT,
        *ids: StreamIdT,
        ref_policy: Literal["KEEPREF", "DELREF", "ACKED"] = "KEEPREF",
    ) -> int | Awaitable[int]:
        """
        Extended version of XDEL that provides more control over how message entries
        are deleted concerning consumer groups.
        """
        if not ids:
            raise DataError("XDELEX requires at least one message ID")

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

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

    @overload
    def xgroup_create(
        self: SyncClientProtocol,
        name: KeyT,
        groupname: GroupT,
        id: StreamIdT = "$",
        mkstream: bool = False,
        entries_read: int | None = None,
    ) -> bool: ...

    @overload
    def xgroup_create(
        self: AsyncClientProtocol,

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Use the exact uppercase token: 'KEEPREF', 'DELREF', or 'ACKED'.
  2. Map config strings: policy = {'keep':'KEEPREF','del':'DELREF','acked':'ACKED'}[cfg].upper().
  3. Omit ref_policy entirely to get the KEEPREF default; do not pass None.

Example fix

# before
r.xdelex('s', *ids, ref_policy='keepref')
# after
r.xdelex('s', *ids, ref_policy='KEEPREF')
Defensive patterns

Strategy: validation

Validate before calling

VALID = {'KEEPREF','DELREF','ACKED'}
policy = str(raw).upper()
if policy not in VALID:
    raise ValueError(f'ref_policy must be one of {VALID}')
r.xdelex(name, *ids, ref_policy=policy)

Type guard

def is_valid_ref_policy(v) -> bool:
    return v in {'KEEPREF','DELREF','ACKED'}

Try / catch

from redis.exceptions import DataError
try:
    r.xdelex(name, *ids, ref_policy=p)
except DataError:
    r.xdelex(name, *ids, ref_policy='KEEPREF')

Prevention

When it happens

Trigger: xdelex(..., ref_policy='delete'), ='keepref' (lowercase), ='NONE', =None. Only the exact uppercase tokens pass.

Common situations: Lowercasing policy names from config; using a different vocabulary (DELETE/REMOVE); passing None expecting the default (the default only applies when the kwarg is omitted, not when explicitly None - None fails the set test).

Related errors


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