{"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/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/core.py#L2765-L2801","documentation":"bitpos() searches for the first occurrence of a specific bit value, so the bit argument must be exactly 0 or 1. Any other integer (or value) is rejected at core.py:2782 with DataError because Redis has no other bit states to find.","triggerScenarios":"r.bitpos('key', 2), r.bitpos('key', bit=-1), or passing a computed/validated value that fell outside {0,1}.","commonSituations":"Passing a user-supplied or computed flag without clamping to binary; off-by-one in a loop variable fed into bitpos.","solutions":["Pass bit=0 or bit=1 explicitly.","Clamp/sanitize external input before calling: bit = 1 if value else 0.","Add a precondition assert or if-check at the call site for clarity."],"exampleFix":"# before\npos = r.bitpos('key', bit=flag)  # flag may be 2\n\n# after\npos = r.bitpos('key', bit=1 if flag else 0)","handlingStrategy":"validation","validationCode":"if bit not in (0, 1):\n    bit = 1 if bit else 0\nr.bitpos('key', bit)","typeGuard":"def is_valid_bit(bit: int) -> bool:\n    return bit in (0, 1)","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    r.bitpos('key', bit)\nexcept DataError as e:\n    if 'bit must be 0 or 1' in str(e):\n        r.bitpos('key', 1 if bit else 0)\n    else:\n        raise","preventionTips":["Normalize external flags to 0/1 before passing to bitpos.","Treat bit as a boolean and convert with int(flag)."],"tags":["redis","bitpos","validation","arguments"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}