redis/redis-py · error · Exception
nx and xx are mutually exclusive: use one, the other or neit
Error message
nx and xx are mutually exclusive: use one, the other or neither - but not both
What it means
Raised by JSON.set() when both nx=True and xx=True are passed. NX means 'only set if the key/path does not exist'; XX means 'only set if it exists' — they are logically contradictory. Note: unlike most redis-py validation errors, this raises a bare Exception (not DataError), so catching redis.exceptions.DataError will NOT catch it.
Source
Thrown at redis/commands/json/commands.py:519
with utf-8.
``fpha`` if set, forces Redis to use the specified floating-point type
for storing all FP homogeneous arrays in ``obj``.
Accepts a :class:`FPHAType` enum value or a string
(``"BF16"``, ``"FP16"``, ``"FP32"``, ``"FP64"``).
For the purpose of using this within a pipeline, this command is also
aliased to JSON.SET.
For more information see `JSON.SET <https://redis.io/commands/json.set>`_.
"""
if decode_keys:
obj = decode_dict_keys(obj)
pieces = [name, str(path), self._encode(obj)]
# Handle existential modifiers
if nx and xx:
raise Exception(
"nx and xx are mutually exclusive: use one, the "
"other or neither - but not both"
)
elif nx:
pieces.append("NX")
elif xx:
pieces.append("XX")
if fpha is not None:
pieces.extend(["FPHA", FPHAType.from_value(fpha).value])
return self.execute_command("JSON.SET", *pieces)
@overload
def mset(
self: SyncClientProtocol, triplets: list[tuple[str, str, JsonType]]
) -> bool: ...
View on GitHub (pinned to da03cdc7e8)
Solutions
- Pass at most one of nx or xx (or neither for unconditional set).
- Derive both from a single tri-state variable: nx = (mode == 'create'), xx = (mode == 'update').
- Catch the bare Exception around JSON.set if the flags come from untrusted input.
Example fix
// before
client.json().set("k", "$", obj, nx=True, xx=True)
// after
client.json().set("k", "$", obj, nx=True) # only-if-absent Defensive patterns
Strategy: validation
Validate before calling
def json_set(client, name, path, obj, mode=None):
if mode not in (None, "create", "update"):
raise ValueError(f"mode must be None/create/update, got {mode}")
return client.json().set(
name, path, obj,
nx=(mode == "create"),
xx=(mode == "update"),
) Type guard
def valid_nx_xx(nx, xx) -> bool:
return not (nx and xx) Try / catch
# Note: this raises bare Exception, NOT DataError.
try:
client.json().set("k", "$", obj, nx=nx, xx=xx)
except Exception as e:
if "mutually exclusive" in str(e):
# pick one based on intent
client.json().set("k", "$", obj, nx=True)
else:
raise Prevention
- Derive nx/xx from a single tri-state variable so both can never be true.
- Don't catch DataError expecting to handle this — it's a bare Exception.
- Validate `not (nx and xx)` at the boundary before the call.
When it happens
Trigger: Call client.json().set(name, path, obj, nx=True, xx=True).
Common situations: Building the nx/xx flags from a single mode variable and accidentally setting both (e.g. flags parsed from a request where both fields were present); copy-paste leaving a stale nx=True.
Related errors
- Invalid FPHA type: {value}. Must be one of {', '.join(t.valu
- The only valid subcommands are
- No key specified
- Subcommand {subcommand_name} not found in command {command_n
- Command {command_name} not found in commands
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/d921575f880ce8bc.json.
Report an issue: GitHub.