redis/redis-py · error · DataError
XCLAIM force must be a boolean
Error message
XCLAIM force must be a boolean
What it means
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.
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.
Example fix
# before
r.xclaim('s','g','c', 0, ['1-0'], force='true')
# after
r.xclaim('s','g','c', 0, ['1-0'], force=True) Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(force, bool):
raise TypeError('force must be bool, got %r' % type(force)) Type guard
lambda v: isinstance(v, bool)
Try / catch
from redis.exceptions import DataError
try:
r.xclaim('s','g','c', 0, ids, force=force)
except DataError as e:
log.warning('bad xclaim force %r: %s', force, e) Prevention
- Use True/False literally for force.
- Because the guard only fires on truthy values, force=0 hides a type bug -- validate explicitly.
When it happens
Trigger: Calling r.xclaim(..., force=1), force='true', or force='yes'. force=True passes; force=0/False/None skip the check entirely.
Common situations: Passing a 'truthy' string from CLI/config to enable force, or using 1/0 instead of True/False.
Related errors
- XCLAIM justid must be a boolean
- XCLAIM idle must be an integer
- XCLAIM message_ids must be a non empty list or tuple of…
- XCLAIM min_idle_time must be a non negative integer
- XCLAIM retrycount must be an integer
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/8c9dbbe5481f4392.
Report an issue: GitHub.
Appendix: source
Thrown at redis/commands/core.py:7319
pieces: list[EncodableT] = [name, groupname, consumername, str(min_idle_time)]
pieces.extend(list(message_ids))
if idle is not None:
if not isinstance(idle, int):
raise DataError("XCLAIM idle must be an integer")
pieces.extend((b"IDLE", str(idle)))
if time is not None:
if not isinstance(time, int):
raise DataError("XCLAIM time must be an integer")
pieces.extend((b"TIME", str(time)))
if retrycount is not None:
if not isinstance(retrycount, int):
raise DataError("XCLAIM retrycount must be an integer")
pieces.extend((b"RETRYCOUNT", str(retrycount)))
if force:
if not isinstance(force, bool):
raise DataError("XCLAIM force must be a boolean")
pieces.append(b"FORCE")
if justid:
if not isinstance(justid, bool):
raise DataError("XCLAIM justid must be a boolean")
pieces.append(b"JUSTID")
kwargs["parse_justid"] = True
return self.execute_command("XCLAIM", *pieces, **kwargs)
@overload
def xdel(self: SyncClientProtocol, name: KeyT, *ids: StreamIdT) -> int: ...
@overload
def xdel(
self: AsyncClientProtocol, name: KeyT, *ids: StreamIdT
) -> Awaitable[int]: ...
def xdel(self, name: KeyT, *ids: StreamIdT) -> int | Awaitable[int]:
"""View on GitHub (pinned to 6a6b581b48)