redis/redis-py · error · DataError

XCLAIM justid must be a boolean

Error message

XCLAIM justid must be a boolean

What it means

Raised by Redis.xclaim() when justid is truthy but not a bool. Like force, the check runs only inside `if justid:`. justid returns only claimed IDs without message bodies.

Solutions

  1. Pass a real bool: justid=True/False.
  2. Coerce config flags with bool().

Example fix

# before
r.xclaim('s','g','c', 0, ['1-0'], justid=1)

# after
r.xclaim('s','g','c', 0, ['1-0'], justid=True)
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(justid, bool):
    raise TypeError('justid must be bool')

Type guard

lambda v: isinstance(v, bool)

Try / catch

from redis.exceptions import DataError
try:
    r.xclaim('s','g','c', 0, ids, justid=j)
except DataError as e:
    log.warning('bad xclaim justid %r: %s', j, e)

Prevention

When it happens

Trigger: Calling r.xclaim(..., justid=1) or justid='true'. justid=True passes; falsy values skip the check.

Common situations: Using 1/0 or strings instead of True/False, or toggling justid from a config flag.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/d0903dd698b75c92. Report an issue: GitHub.

Appendix: source

Thrown at redis/commands/core.py:7323

            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]:
        """
        Deletes one or more messages from a stream.

        Args:
            name: name of the stream.

View on GitHub (pinned to 6a6b581b48)