redis/redis-py · error · ValueError
Only one of IFEQ/IFNE/IFDEQ/IFDNE may be specified
Error message
Only one of IFEQ/IFNE/IFDEQ/IFDNE may be specified
What it means
delex() (experimental, Redis 8.4+) accepts at most one conditional modifier among IFEQ, IFNE, IFDEQ, IFDNE. Passing two or more is contradictory (you cannot require both equal-and-not-equal) and is rejected at core.py:2931 with ValueError. Note this raises ValueError, not DataError.
Source
Thrown at redis/commands/core.py:2932
ifeq match-valu: Optional[Union[bytes, str]] - Delete the key only if its value is equal to match-value
ifne match-value: Optional[Union[bytes, str]] - Delete the key only if its value is not equal to match-value
ifdeq match-digest: Optional[str] - Delete the key only if the digest of its value is equal to match-digest
ifdne match-digest: Optional[str] - Delete the key only if the digest of its value is not equal to match-digest
Returns:
int: 1 if the key was deleted, 0 otherwise.
Raises:
redis.exceptions.ResponseError: if key exists but is not a string
and a condition is specified.
ValueError: if more than one condition is provided.
Requires Redis 8.4 or greater.
For more information, see https://redis.io/commands/delex
"""
conds = [x is not None for x in (ifeq, ifne, ifdeq, ifdne)]
if sum(conds) > 1:
raise ValueError("Only one of IFEQ/IFNE/IFDEQ/IFDNE may be specified")
pieces = ["DELEX", name]
if ifeq is not None:
pieces += ["IFEQ", ifeq]
elif ifne is not None:
pieces += ["IFNE", ifne]
elif ifdeq is not None:
pieces += ["IFDEQ", ifdeq]
elif ifdne is not None:
pieces += ["IFDNE", ifdne]
return self.execute_command(*pieces)
@overload
def dump(self: SyncClientProtocol, name: KeyT) -> bytes | None: ...
@overload
def dump(self: AsyncClientProtocol, name: KeyT) -> Awaitable[bytes | None]: ...View on GitHub (pinned to da03cdc7e8)
Solutions
- Pass exactly one condition keyword, e.g. r.delex('key', ifeq='expected').
- If you need multi-condition logic, issue separate delex calls or implement client-side comparison after a GET.
- Catch ValueError specifically (not DataError) when wrapping delex in error handling.
Example fix
# before
r.delex('key', ifeq='a', ifne='b')
# after
r.delex('key', ifeq='a') # pick the single condition you actually need Defensive patterns
Strategy: validation
Validate before calling
conds = [ifeq, ifne, ifdeq, ifdne]
if sum(c is not None for c in conds) > 1:
raise ValueError('delex: pass at most one of ifeq/ifne/ifdeq/ifdne')
r.delex('key', ifeq=ifeq, ifne=ifne, ifdeq=ifdeq, ifdne=ifdne) Type guard
def valid_delex_conditions(ifeq, ifne, ifdeq, ifdne) -> bool:
return sum(x is not None for x in (ifeq, ifne, ifdeq, ifdne)) <= 1 Try / catch
try:
r.delex('key', ifeq=ifeq, ifne=ifne, ifdeq=ifdeq, ifdne=ifdne)
except ValueError as e:
if 'Only one of IFEQ' in str(e):
# pick the highest-priority condition and retry
r.delex('key', ifeq=ifeq)
else:
raise Prevention
- Remember delex raises ValueError, not DataError, so catch the right type.
- Model the condition as a single (op, value) pair in your API rather than four kwargs.
When it happens
Trigger: r.delex('key', ifeq='a', ifne='b'), or r.delex('key', ifdeq=digest, ifdne=other). Any pair of the four condition kwargs triggers sum(conds) > 1.
Common situations: Building a generic conditional-delete helper that forwards multiple optional filters; misunderstanding the semantics and assuming conditions are AND-combined.
Related errors
- ``byfloat`` and ``byint`` are mutually exclusive.
- Both start and end must be specified
- start argument is not set, when end is specified
- ``ex``, ``px``, ``exat``, ``pxat``, and ``persist`` are mutu
- ``enx`` requires one of ``ex``, ``px``, ``exat``, or ``pxat`
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/825521623d1d4b05.json.
Report an issue: GitHub.