{"record":{"id":"8c9dbbe5481f4392","repo":"redis/redis-py","slug":"xclaim-force-must-be-a-boolean","errorCode":null,"errorMessage":"XCLAIM force must be a boolean","messagePattern":"XCLAIM force must be a boolean","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":7319,"sourceCode":"        pieces: list[EncodableT] = [name, groupname, consumername, str(min_idle_time)]\n        pieces.extend(list(message_ids))\n\n        if idle is not None:\n            if not isinstance(idle, int):\n                raise DataError(\"XCLAIM idle must be an integer\")\n            pieces.extend((b\"IDLE\", str(idle)))\n        if time is not None:\n            if not isinstance(time, int):\n                raise DataError(\"XCLAIM time must be an integer\")\n            pieces.extend((b\"TIME\", str(time)))\n        if retrycount is not None:\n            if not isinstance(retrycount, int):\n                raise DataError(\"XCLAIM retrycount must be an integer\")\n            pieces.extend((b\"RETRYCOUNT\", str(retrycount)))\n\n        if force:\n            if not isinstance(force, bool):\n                raise DataError(\"XCLAIM force must be a boolean\")\n            pieces.append(b\"FORCE\")\n        if justid:\n            if not isinstance(justid, bool):\n                raise DataError(\"XCLAIM justid must be a boolean\")\n            pieces.append(b\"JUSTID\")\n            kwargs[\"parse_justid\"] = True\n        return self.execute_command(\"XCLAIM\", *pieces, **kwargs)\n\n    @overload\n    def xdel(self: SyncClientProtocol, name: KeyT, *ids: StreamIdT) -> int: ...\n\n    @overload\n    def xdel(\n        self: AsyncClientProtocol, name: KeyT, *ids: StreamIdT\n    ) -> Awaitable[int]: ...\n\n    def xdel(self, name: KeyT, *ids: StreamIdT) -> int | Awaitable[int]:\n        \"\"\"","sourceCodeStart":7301,"sourceCodeEnd":7337,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L7301-L7337","documentation":"Raised by Redis.xclaim() when force is truthy but not a bool. The check runs only inside `if force:`, so falsy values (False, 0, None, '') skip it. Truthy non-bool values like 1, 'yes', or 'true' fail isinstance(bool). force creates a PEL entry even if the IDs are not already pending.","triggerScenarios":"Calling r.xclaim(..., force=1), force='true', or force='yes'. force=True passes; force=0/False/None skip the check entirely.","commonSituations":"Passing a 'truthy' string from CLI/config to enable force, or using 1/0 instead of True/False.","solutions":["Pass a real bool: force=True or force=False.","Coerce config: force = bool(str_val.lower() == 'true').","Do not use 1/0 or strings for force."],"exampleFix":"# before\nr.xclaim('s','g','c', 0, ['1-0'], force='true')\n\n# after\nr.xclaim('s','g','c', 0, ['1-0'], force=True)","handlingStrategy":"type-guard","validationCode":"if not isinstance(force, bool):\n    raise TypeError('force must be bool, got %r' % type(force))","typeGuard":"lambda v: isinstance(v, bool)","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    r.xclaim('s','g','c', 0, ids, force=force)\nexcept DataError as e:\n    log.warning('bad xclaim force %r: %s', force, e)","preventionTips":["Use True/False literally for force.","Because the guard only fires on truthy values, force=0 hides a type bug -- validate explicitly."],"tags":["stream","xclaim","validation","boolean-coercion"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}