redis/redis-py · error · DataError

bit must be 0 or 1

Error message

bit must be 0 or 1

What it means

Raised as a `DataError` by `bitpos()` (redis/commands/core.py:2782) when `bit not in (0, 1)`. BITPOS searches for the first occurrence of either a 0 or 1 bit; any other value is meaningless, so it is rejected client-side.

Solutions

  1. Pass the literal int `0` or `1`.
  2. Coerce and validate user input first: `b = int(user_val); assert b in (0, 1)`.
  3. If you have a boolean, it already works, but cast explicitly for clarity.

Example fix

// before
r.bitpos('k', int(user_input))  # user_input could be '2'
// after
b = int(user_input)
if b not in (0, 1):
    raise ValueError('bit must be 0 or 1')
r.bitpos('k', b)
Defensive patterns

Strategy: type-guard

Validate before calling

b = int(user_val)
if b not in (0, 1):
    raise ValueError('bit must be 0 or 1')
r.bitpos('k', b)

Type guard

def is_bit(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool) and v in (0, 1) or (isinstance(v, bool))

Prevention

When it happens

Trigger: `r.bitpos('k', 2)`, `r.bitpos('k', -1)`, or passing a computed/typed value (e.g. an enum or string '1') that is not literally the int 0 or 1. Note Python `True`/`False` pass because they equal 1/0.

Common situations: User input parsed as a string or float ('1' → not in (0,1)); counters/IDs mistakenly used as the bit argument; config-driven code passing an enum's underlying value other than 0/1.

Related errors


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

Appendix: source

Thrown at redis/commands/core.py:2783

    def bitpos(
        self,
        key: KeyT,
        bit: int,
        start: int | None = None,
        end: int | None = None,
        mode: str | None = None,
    ) -> int | Awaitable[int]:
        """
        Return the position of the first bit set to 1 or 0 in a string.
        ``start`` and ``end`` defines search range. The range is interpreted
        as a range of bytes and not a range of bits, so start=0 and end=2
        means to look at the first three bytes.

        For more information, see https://redis.io/commands/bitpos
        """
        if bit not in (0, 1):
            raise DataError("bit must be 0 or 1")
        params = [key, bit]

        start is not None and params.append(start)

        if start is not None and end is not None:
            params.append(end)
        elif start is None and end is not None:
            raise DataError("start argument is not set, when end is specified")

        if mode is not None:
            params.append(mode)
        return self.execute_command("BITPOS", *params, keys=[key])

    @overload
    def copy(
        self: SyncClientProtocol,
        source: str,
        destination: str,

View on GitHub (pinned to 6a6b581b48)