redis/redis-py · error · Exception
nx and xx are mutually exclusive: use one, the other or…
Error message
nx and xx are mutually exclusive: use one, the other or neither - but not both
What it means
Raised by JSON SET (redis/commands/json/commands.py:519) as a plain Exception (not DataError - inconsistent with the rest of the module) when both nx=True and xx=True. NX means set only if the key/path does not exist; XX means set only if it exists - they are logically contradictory so the library rejects the combination before sending JSON.SET.
Solutions
- Pass at most one of nx or xx (or neither for unconditional set).
- Decide the intended semantics: nx = create-only, xx = update-only.
- If building flags dynamically, assert not (nx and xx) before the call.
Example fix
# before
client.json().set('doc', '$', obj, nx=create_only, xx=update_only)
# after
if create_only and update_only:
raise ValueError('cannot be both create-only and update-only')
client.json().set('doc', '$', obj, nx=create_only, xx=update_only) Defensive patterns
Strategy: validation
Validate before calling
def json_set_flags(nx, xx):
if nx and xx:
raise ValueError('nx and xx are mutually exclusive')
return nx, xx Type guard
def valid_json_set_mode(nx, xx) -> bool:
return not (nx and xx) Try / catch
# NOTE: this raises a bare Exception, NOT DataError - catch broadly
try:
client.json().set('k', '$', obj, nx=nx, xx=xx)
except Exception as e:
if 'mutually exclusive' in str(e):
# pick one mode explicitly
client.json().set('k', '$', obj, nx=True)
else:
raise Prevention
- Never set both nx and xx; assert not (nx and xx) before the call.
- Decide create-only (nx) vs update-only (xx) at the call site.
- Remember this is a bare Exception - a DataError-only handler will miss it.
When it happens
Trigger: Calling client.json().set(key, path, obj, nx=True, xx=True). Any code path that sets both flags True (e.g. building kwargs dynamically and both end up set).
Common situations: Conditional logic that flips both flags, copy-paste from two examples, or a config object that enables both modes. Because this is a bare Exception (not DataError), a broad `except DataError` will NOT catch it.
Related errors
- Invalid FPHA type: . Must be one of
- No key specified
- The only valid subcommands are
- AGGREGATION requires exactly one aggregation spec per key
- At least one key must be provided.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/d921575f880ce8bc.
Report an issue: GitHub.
Appendix: 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 6a6b581b48)