redis/redis-py · error · DataError

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

Error message

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

What it means

Raised as a `DataError` by `msetex()` (redis/commands/core.py:3875) via `at_most_one_value_set(...)` when more than one of `ex`, `px`, `exat`, `pxat`, or `keepttl` is set. MSETEX (Redis 8.4+) applies one TTL policy across the whole key/value mapping; mixing them is rejected client-side.

Solutions

  1. Set exactly one of `ex`, `px`, `exat`, `pxat`, or `keepttl=True`.
  2. Resolve a single TTL policy before calling and forward only that kwarg.
  3. Validate with the same `at_most_one_value_set` helper if you wrap MSETEX.

Example fix

// before
r.msetex({'a': 1, 'b': 2}, ex=10, keepttl=True)
// after
r.msetex({'a': 1, 'b': 2}, ex=10)  # 10s TTL on both keys
Defensive patterns

Strategy: validation

Validate before calling

expiry = [a for a in (ex, px, exat, pxat) if a is not None]
if len(expiry) + (1 if keepttl else 0) > 1:
    raise ValueError('msetex: at most one of ex/px/exat/pxat/keepttl')
r.msetex(mapping, **({} if not expiry else {'ex': expiry[0]}), keepttl=keepttl)

Prevention

When it happens

Trigger: `r.msetex({'a': 1, 'b': 2}, ex=10, keepttl=True)`, or any MSETEX call combining two or more expiry kwargs.

Common situations: Shared expiry helpers reused across SET/MSETEX; config objects carrying both a TTL and a keepttl flag; refactoring that leaves stale kwargs in place.

Related errors


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

Appendix: source

Thrown at redis/commands/core.py:3884

            specified in unix time.

        ``keepttl`` if True, retain the time to live associated with the keys.

        Returns the number of fields that were added.

        Available since Redis 8.4
        For more information, see https://redis.io/commands/msetex
        """
        if not at_most_one_value_set(
            (
                ex is not None,
                px is not None,
                exat is not None,
                pxat is not None,
                keepttl,
            )
        ):
            raise DataError(
                "``ex``, ``px``, ``exat``, ``pxat``, "
                "and ``keepttl`` are mutually exclusive."
            )

        exp_options: list[EncodableT] = []
        if data_persist_option:
            exp_options.append(data_persist_option.value)

        exp_options.extend(extract_expire_flags(ex, px, exat, pxat))

        if keepttl:
            exp_options.append("KEEPTTL")

        pieces = ["MSETEX", len(mapping)]

        for pair in mapping.items():
            pieces.extend(pair)

View on GitHub (pinned to 6a6b581b48)