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
- Pass the literal int `0` or `1`.
- Coerce and validate user input first: `b = int(user_val); assert b in (0, 1)`.
- 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
- Coerce user input to int and assert membership in {0,1}.
- Avoid passing floats/strings/enums as the bit argument.
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
- start argument is not set, when end is specified
- Both start and end must be specified
- ``byfloat`` and ``byint`` are mutually exclusive.
- ``count`` is required when ``mode`` or ``ordering`` is set
- ``enx`` requires one of ``ex``, ``px``, ``exat``, or…
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)