redis/redis-py · error · DataError

start argument is not set, when end is specified

Error message

start argument is not set, when end is specified

What it means

bitpos() interprets an optional search range as [start, end]; end is only meaningful with a start. The guard at core.py:2790 rejects an end without a start because Redis BITPOS positional args require start before end.

Source

Thrown at redis/commands/core.py:2791

    ) -> 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,
        destination_db: str | None = None,
        replace: bool = False,
    ) -> bool: ...

    @overload
    def copy(
        self: AsyncClientProtocol,
        source: str,

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Always provide start when you provide end, e.g. r.bitpos('key', 1, start=0, end=10).
  2. If you want the whole string, omit both start and end.
  3. When constructing from optional config, set start=0 as the default whenever end is provided.

Example fix

# before
r.bitpos('key', 1, end=10)

# after
r.bitpos('key', 1, start=0, end=10)
Defensive patterns

Strategy: validation

Validate before calling

if end is not None and start is None:
    start = 0
r.bitpos('key', bit, start=start, end=end)

Type guard

def valid_bitpos_range(start, end) -> bool:
    return not (end is not None and start is None)

Try / catch

from redis.exceptions import DataError
try:
    r.bitpos('key', bit, start=start, end=end)
except DataError as e:
    if 'start argument is not set' in str(e):
        r.bitpos('key', bit, start=0, end=end)
    else:
        raise

Prevention

When it happens

Trigger: r.bitpos('key', 1, end=10) with start left at its default None. The elif at core.py:2790 catches start is None and end is not None.

Common situations: Calling bitpos with keyword-only end expecting it to mean 'first 10 bytes'; refactoring that dropped the start argument; building params from a dict that only set end.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/0ff909dfedb09ef5.json. Report an issue: GitHub.