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

  1. Pass at most one of nx or xx (or neither for unconditional set).
  2. Decide the intended semantics: nx = create-only, xx = update-only.
  3. 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

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


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)