{"id":"5ba1719a36c9eb88","repo":"redis/redis-py","slug":"xdelex-ref-policy-must-be-one-of-keepref-delref","errorCode":null,"errorMessage":"XDELEX ref_policy must be one of: KEEPREF, DELREF, ACKED","messagePattern":"XDELEX ref_policy must be one of: KEEPREF, DELREF, ACKED","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":7378,"sourceCode":"        *ids: StreamIdT,\n        ref_policy: Literal[\"KEEPREF\", \"DELREF\", \"ACKED\"] = \"KEEPREF\",\n    ) -> Awaitable[int]: ...\n\n    def xdelex(\n        self,\n        name: KeyT,\n        *ids: StreamIdT,\n        ref_policy: Literal[\"KEEPREF\", \"DELREF\", \"ACKED\"] = \"KEEPREF\",\n    ) -> int | Awaitable[int]:\n        \"\"\"\n        Extended version of XDEL that provides more control over how message entries\n        are deleted concerning consumer groups.\n        \"\"\"\n        if not ids:\n            raise DataError(\"XDELEX requires at least one message ID\")\n\n        if ref_policy not in {\"KEEPREF\", \"DELREF\", \"ACKED\"}:\n            raise DataError(\"XDELEX ref_policy must be one of: KEEPREF, DELREF, ACKED\")\n\n        pieces = [name, ref_policy, \"IDS\", len(ids)]\n        pieces.extend(ids)\n        return self.execute_command(\"XDELEX\", *pieces)\n\n    @overload\n    def xgroup_create(\n        self: SyncClientProtocol,\n        name: KeyT,\n        groupname: GroupT,\n        id: StreamIdT = \"$\",\n        mkstream: bool = False,\n        entries_read: int | None = None,\n    ) -> bool: ...\n\n    @overload\n    def xgroup_create(\n        self: AsyncClientProtocol,","sourceCodeStart":7360,"sourceCodeEnd":7396,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/core.py#L7360-L7396","documentation":"Raised by xdelex() when ref_policy is not one of KEEPREF, DELREF, ACKED. Case-SENSITIVE membership test at core.py:7377. Default is KEEPREF.","triggerScenarios":"xdelex(..., ref_policy='delete'), ='keepref' (lowercase), ='NONE', =None. Only the exact uppercase tokens pass.","commonSituations":"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).","solutions":["Use the exact uppercase token: 'KEEPREF', 'DELREF', or 'ACKED'.","Map config strings: policy = {'keep':'KEEPREF','del':'DELREF','acked':'ACKED'}[cfg].upper().","Omit ref_policy entirely to get the KEEPREF default; do not pass None."],"exampleFix":"# before\nr.xdelex('s', *ids, ref_policy='keepref')\n# after\nr.xdelex('s', *ids, ref_policy='KEEPREF')","handlingStrategy":"validation","validationCode":"VALID = {'KEEPREF','DELREF','ACKED'}\npolicy = str(raw).upper()\nif policy not in VALID:\n    raise ValueError(f'ref_policy must be one of {VALID}')\nr.xdelex(name, *ids, ref_policy=policy)","typeGuard":"def is_valid_ref_policy(v) -> bool:\n    return v in {'KEEPREF','DELREF','ACKED'}","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    r.xdelex(name, *ids, ref_policy=p)\nexcept DataError:\n    r.xdelex(name, *ids, ref_policy='KEEPREF')","preventionTips":["Policy tokens are case-sensitive uppercase.","Omit the kwarg for the default rather than passing None."],"tags":["redis","streams","xdelex","validation","enum-error"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}