{"id":"fdd904a9d7fe3b9a","repo":"redis/redis-py","slug":"both-start-and-end-must-be-specified","errorCode":null,"errorMessage":"Both start and end must be specified","messagePattern":"Both start and end must be specified","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":2668,"sourceCode":"    def bitcount(\n        self,\n        key: KeyT,\n        start: int | None = None,\n        end: int | None = None,\n        mode: str | None = None,\n    ) -> int | Awaitable[int]:\n        \"\"\"\n        Returns the count of set bits in the value of ``key``.  Optional\n        ``start`` and ``end`` parameters indicate which bytes to consider\n\n        For more information, see https://redis.io/commands/bitcount\n        \"\"\"\n        params = [key]\n        if start is not None and end is not None:\n            params.append(start)\n            params.append(end)\n        elif (start is not None and end is None) or (end is not None and start is None):\n            raise DataError(\"Both start and end must be specified\")\n        if mode is not None:\n            params.append(mode)\n        return self.execute_command(\"BITCOUNT\", *params, keys=[key])\n\n    def bitfield(\n        self: Union[\"redis.client.Redis\", \"redis.asyncio.client.Redis\"],\n        key: KeyT,\n        default_overflow: str | None = None,\n    ) -> BitFieldOperation:\n        \"\"\"\n        Return a BitFieldOperation instance to conveniently construct one or\n        more bitfield operations on ``key``.\n\n        For more information, see https://redis.io/commands/bitfield\n        \"\"\"\n        return BitFieldOperation(self, key, default_overflow=default_overflow)\n\n    @overload","sourceCodeStart":2650,"sourceCodeEnd":2686,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/core.py#L2650-L2686","documentation":"bitcount() requires start and end to be supplied together or both omitted; specifying only one is ambiguous (Redis BITCOUNT needs a closed range). The guard at core.py:2667 rejects the half-specified range with DataError before sending a malformed command.","triggerScenarios":"r.bitcount('key', start=0) with no end, or r.bitcount('key', end=10) with no start. Both trigger the XOR branch in the elif.","commonSituations":"Dynamically building kwargs from optional CLI flags or config where only one bound was populated; refactoring from an older API that defaulted the missing bound.","solutions":["Pass both start and end as a pair, e.g. r.bitcount('key', start=0, end=10).","Omit both to count over the whole string, e.g. r.bitcount('key').","When building params dynamically, default the missing bound explicitly (start=0 when only end is given, end=-1 when only start is given)."],"exampleFix":"# before\nr.bitcount('key', start=0)\n\n# after\nr.bitcount('key', start=0, end=10)","handlingStrategy":"validation","validationCode":"if (start is None) != (end is None):\n    raise ValueError('bitcount: provide both start and end, or neither')\nr.bitcount('key', start=start, end=end)","typeGuard":"def valid_bitcount_range(start, end) -> bool:\n    return (start is None) == (end is None)","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    r.bitcount('key', start=start, end=end)\nexcept DataError as e:\n    if 'Both start and end' in str(e):\n        end = -1 if end is None else end\n        start = 0 if start is None else start\n        r.bitcount('key', start=start, end=end)\n    else:\n        raise","preventionTips":["Always pass start and end as a tuple/pair from a single config source.","Use r.bitcount('key') with no range when you want the whole string."],"tags":["redis","bitcount","validation","parameter-conflict","range"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}