redis/redis-py · error · DataError
``ex``, ``px``, ``exat``, ``pxat``, and ``persist`` are mutu
Error message
``ex``, ``px``, ``exat``, ``pxat``, and ``persist`` are mutually exclusive.
What it means
getex() sets or removes a key's TTL via exactly one mechanism. ex (seconds), px (ms), exat (unix-seconds), pxat (unix-ms), and persist are mutually exclusive; at most one may be set. The at_most_one_value_set check at core.py:3274 enforces this with DataError.
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 da03cdc7e8)
Solutions
- Choose one expiry unit and pass only it, e.g. r.getex('key', ex=60).
- Use persist=True alone to strip the TTL, or an expiry option alone to set it.
- Centralize expiry selection in a helper that returns exactly one of the five.
Example fix
# before
r.getex('key', ex=60, px=60000)
# after
r.getex('key', ex=60) # pick one unit Defensive patterns
Strategy: validation
Validate before calling
expiry = {'ex': ex, 'px': px, 'exat': exat, 'pxat': pxat}
if persist:
expiry['persist'] = True
set_count = sum(v is not None and v is not False for v in expiry.values())
if set_count > 1:
raise ValueError('getex: pass exactly one expiry option')
r.getex('key', **expiry) Type guard
def valid_single_expiry(ex, px, exat, pxat, persist) -> bool:
return sum(bool(x) for x in (ex, px, exat, pxat, persist)) <= 1 Try / catch
from redis.exceptions import DataError
try:
r.getex('key', ex=ex, px=px)
except DataError as e:
if 'mutually exclusive' in str(e):
r.getex('key', ex=ex) # keep one, drop the rest
else:
raise Prevention
- Resolve to a single expiry kwarg in a helper before calling getex.
- Treat persist as an alternative to expiry, never combined.
When it happens
Trigger: r.getex('key', ex=10, px=1000), r.getex('key', exat=..., persist=True), or any combination of two or more of the five options.
Common situations: Generic TTL helper that forwards multiple optional kwargs; config-driven expiry where seconds and ms were both populated; refactoring from set() which uses keepttl instead of persist.
Related errors
- ``ex``, ``px``, ``exat``, ``pxat``, and ``keepttl`` are mutu
- Both start and end must be specified
- start argument is not set, when end is specified
- Only one of IFEQ/IFNE/IFDEQ/IFDNE may be specified
- ``byfloat`` and ``byint`` are mutually exclusive.
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/5676bf36fbc0698f.json.
Report an issue: GitHub.