{"record":{"id":"590d77c341687f84","repo":"redis/redis-py","slug":"bit-must-be-0-or-1","errorCode":null,"errorMessage":"bit must be 0 or 1","messagePattern":"bit must be 0 or 1","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":2783,"sourceCode":"\n    def bitpos(\n        self,\n        key: KeyT,\n        bit: int,\n        start: int | None = None,\n        end: int | None = None,\n        mode: str | None = None,\n    ) -> int | Awaitable[int]:\n        \"\"\"\n        Return the position of the first bit set to 1 or 0 in a string.\n        ``start`` and ``end`` defines search range. The range is interpreted\n        as a range of bytes and not a range of bits, so start=0 and end=2\n        means to look at the first three bytes.\n\n        For more information, see https://redis.io/commands/bitpos\n        \"\"\"\n        if bit not in (0, 1):\n            raise DataError(\"bit must be 0 or 1\")\n        params = [key, bit]\n\n        start is not None and params.append(start)\n\n        if start is not None and end is not None:\n            params.append(end)\n        elif start is None and end is not None:\n            raise DataError(\"start argument is not set, when end is specified\")\n\n        if mode is not None:\n            params.append(mode)\n        return self.execute_command(\"BITPOS\", *params, keys=[key])\n\n    @overload\n    def copy(\n        self: SyncClientProtocol,\n        source: str,\n        destination: str,","sourceCodeStart":2765,"sourceCodeEnd":2801,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L2765-L2801","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\nr.bitpos('k', int(user_input))  # user_input could be '2'\n// after\nb = int(user_input)\nif b not in (0, 1):\n    raise ValueError('bit must be 0 or 1')\nr.bitpos('k', b)","handlingStrategy":"type-guard","validationCode":"b = int(user_val)\nif b not in (0, 1):\n    raise ValueError('bit must be 0 or 1')\nr.bitpos('k', b)","typeGuard":"def is_bit(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v in (0, 1) or (isinstance(v, bool))","tryCatchPattern":null,"preventionTips":["Coerce user input to int and assert membership in {0,1}.","Avoid passing floats/strings/enums as the bit argument."],"tags":["bitpos","arguments","validation","dataerror"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}