redis/redis-py · error · DataError

``ex``, ``px``, ``exat``, ``pxat``, and ``persist`` are…

Error message

``ex``, ``px``, ``exat``, ``pxat``, and ``persist`` are mutually exclusive.

What it means

Raised as a `DataError` by `getex()` (redis/commands/core.py:3274) via `at_most_one_value_set(...)` when more than one of `ex`, `px`, `exat`, `pxat`, or `persist` is set. GETEX sets exactly one expiration policy (or PERSIST to remove TTL); combining them is ambiguous and rejected client-side.

Solutions

  1. Choose exactly one expiration form (seconds via `ex`, ms via `px`, absolute seconds via `exat`, absolute ms via `pxat`, or `persist=True`).
  2. Build the expiry choice through a single resolved variable rather than passing multiple.
  3. Validate with `at_most_one_value_set` yourself if you wrap the call.

Example fix

// before
r.getex('k', ex=10, px=1000)
// after
r.getex('k', ex=10)  # 10-second TTL
Defensive patterns

Strategy: validation

Validate before calling

exp_args = [ex, px, exat, pxat]
set_exp = [a for a in exp_args if a is not None]
if len(set_exp) + (1 if persist else 0) > 1:
    raise ValueError('getex: at most one expiry option allowed')
r.getex('k', **({} if not set_exp else {'ex': set_exp[0]}))

Prevention

When it happens

Trigger: `r.getex('k', ex=10, px=1000)`, `r.getex('k', ex=10, persist=True)`, or any call where two or more of those expiry kwargs are non-None/non-False.

Common situations: Generic 'set expiry' helper that forwards a dict of kwargs and accidentally overlaps; refactoring code that previously set TTL separately; defaults that collide with explicit args.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/5676bf36fbc0698f. Report an issue: GitHub.

Appendix: source

Thrown at redis/commands/core.py:3283

        specified in unix time.

        ``pxat`` sets an expire flag on key ``name`` for ``ex`` milliseconds,
        specified in unix time.

        ``persist`` remove the time to live associated with ``name``.

        For more information, see https://redis.io/commands/getex
        """
        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."
            )

        exp_options: list[EncodableT] = extract_expire_flags(ex, px, exat, pxat)

        if persist:
            exp_options.append("PERSIST")

        return self.execute_command("GETEX", name, *exp_options)

    def __getitem__(self, name: KeyT):
        """
        Return the value at key ``name``, raises a KeyError if the key
        doesn't exist.
        """
        value = self.get(name)
        if value is not None:

View on GitHub (pinned to 6a6b581b48)