redis/redis-py · error · DataError

``byfloat`` and ``byint`` are mutually exclusive.

Error message

``byfloat`` and ``byint`` are mutually exclusive.

What it means

increx() (experimental) increments a value by either a float (BYFLOAT) or an int (BYINT); the two are mutually exclusive because they select different Redis increment modes. The at_most_one_value_set guard at core.py:3478 raises DataError if both are set.

Source

Thrown at redis/commands/core.py:3484

        ``lbound`` and ``ubound`` constrain the valid range of the result.

        If ``saturate`` is True, out-of-bounds results are saturated to the
        specified bound, or to the type limit when no bound is specified.
        Otherwise, out-of-bounds results are rejected, leaving the value and
        TTL unchanged and returning the current value and zero as the actual
        increment.

        ``enx`` applies the expiration only when the key does not already
        have an expiration, and requires ``ex``, ``px``, ``exat``, or ``pxat``.
        """
        if not at_most_one_value_set(
            (
                byfloat is not None,
                byint is not None,
            )
        ):
            raise DataError("``byfloat`` and ``byint`` are mutually exclusive.")

        if not at_most_one_value_set(
            (
                ex is not None,
                px is not None,
                exat is not None,
                pxat is not None,
                persist,
            )
        ):
            raise DataError(
                "``ex``, ``px``, ``exat``, ``pxat``, "
                "and ``persist`` are mutually exclusive."
            )

        if enx and ex is None and px is None and exat is None and pxat is None:
            raise DataError(
                "``enx`` requires one of ``ex``, ``px``, ``exat``, or ``pxat``."

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Pass exactly one of byfloat or byint depending on the value type, e.g. r.increx('counter', byint=5).
  2. Omit both to increment by one.
  3. In a helper, branch on isinstance(value, float) vs int and pass the correct single kwarg.

Example fix

# before
r.increx('counter', byfloat=1.5, byint=2)

# after
r.increx('counter', byfloat=1.5)  # choose one
Defensive patterns

Strategy: validation

Validate before calling

if byfloat is not None and byint is not None:
    raise ValueError('increx: pass byfloat or byint, not both')
r.increx('k', byfloat=byfloat, byint=byint)

Type guard

def valid_increx_amount(byfloat, byint) -> bool:
    return not (byfloat is not None and byint is not None)

Try / catch

from redis.exceptions import DataError
try:
    r.increx('k', byfloat=byfloat, byint=byint)
except DataError as e:
    if 'byfloat and byint' in str(e):
        r.increx('k', byint=byint)  # keep one
    else:
        raise

Prevention

When it happens

Trigger: r.increx('counter', byfloat=1.5, byint=2), or forwarding both from optional kwargs. If neither is set the value increments by one (the default).

Common situations: Generic increment helper that accepts both an int and float path; misunderstanding the API as additive; copy-paste from incrby/incrbyfloat which are separate commands.

Related errors


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