{"id":"d921575f880ce8bc","repo":"redis/redis-py","slug":"nx-and-xx-are-mutually-exclusive-use-one-the-oth","errorCode":null,"errorMessage":"nx and xx are mutually exclusive: use one, the other or neither - but not both","messagePattern":"nx and xx are mutually exclusive: use one, the other or neither - but not both","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"redis/commands/json/commands.py","lineNumber":519,"sourceCode":"        with utf-8.\n        ``fpha`` if set, forces Redis to use the specified floating-point type\n        for storing all FP homogeneous arrays in ``obj``.\n        Accepts a :class:`FPHAType` enum value or a string\n        (``\"BF16\"``, ``\"FP16\"``, ``\"FP32\"``, ``\"FP64\"``).\n\n        For the purpose of using this within a pipeline, this command is also\n        aliased to JSON.SET.\n\n        For more information see `JSON.SET <https://redis.io/commands/json.set>`_.\n        \"\"\"\n        if decode_keys:\n            obj = decode_dict_keys(obj)\n\n        pieces = [name, str(path), self._encode(obj)]\n\n        # Handle existential modifiers\n        if nx and xx:\n            raise Exception(\n                \"nx and xx are mutually exclusive: use one, the \"\n                \"other or neither - but not both\"\n            )\n        elif nx:\n            pieces.append(\"NX\")\n        elif xx:\n            pieces.append(\"XX\")\n\n        if fpha is not None:\n            pieces.extend([\"FPHA\", FPHAType.from_value(fpha).value])\n\n        return self.execute_command(\"JSON.SET\", *pieces)\n\n    @overload\n    def mset(\n        self: SyncClientProtocol, triplets: list[tuple[str, str, JsonType]]\n    ) -> bool: ...\n","sourceCodeStart":501,"sourceCodeEnd":537,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/json/commands.py#L501-L537","documentation":"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.","triggerScenarios":"Call client.json().set(name, path, obj, nx=True, xx=True).","commonSituations":"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.","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."],"exampleFix":"// before\nclient.json().set(\"k\", \"$\", obj, nx=True, xx=True)\n// after\nclient.json().set(\"k\", \"$\", obj, nx=True)  # only-if-absent","handlingStrategy":"validation","validationCode":"def json_set(client, name, path, obj, mode=None):\n    if mode not in (None, \"create\", \"update\"):\n        raise ValueError(f\"mode must be None/create/update, got {mode}\")\n    return client.json().set(\n        name, path, obj,\n        nx=(mode == \"create\"),\n        xx=(mode == \"update\"),\n    )","typeGuard":"def valid_nx_xx(nx, xx) -> bool:\n    return not (nx and xx)","tryCatchPattern":"# Note: this raises bare Exception, NOT DataError.\ntry:\n    client.json().set(\"k\", \"$\", obj, nx=nx, xx=xx)\nexcept Exception as e:\n    if \"mutually exclusive\" in str(e):\n        # pick one based on intent\n        client.json().set(\"k\", \"$\", obj, nx=True)\n    else:\n        raise","preventionTips":["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."],"tags":["redis-json","validation","json-set","mutual-exclusion"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}