{"record":{"id":"fd3454836eead1af","repo":"redis/redis-rb","slug":"nx-and-xx-are-mutually-exclusive","errorCode":null,"errorMessage":"nx and xx are mutually exclusive","messagePattern":"nx and xx are mutually exclusive","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/redis/commands/modules/json.rb","lineNumber":95,"sourceCode":"      # @param [String] path a JSONPath, e.g. \"$\" for the document root\n      # @param [Object] value a JSON-serializable Ruby object, or a pre-encoded JSON string\n      #   when +raw+ is true\n      # @param [Boolean] nx only set when the path does not already exist\n      # @param [Boolean] xx only set when the path already exists\n      # @param [Boolean] raw treat +value+ as an already-encoded JSON string and send it as-is\n      # @param [String, Symbol] fpha store a numeric array as a Floating-Point\n      #   Homogeneous Array of the given precision — one of +:bf16+, +:fp16+,\n      #   +:fp32+, +:fp64+ (case-insensitive; Redis 8.8+). All values of the array\n      #   are forced into the fixed floating-point type: +:bf16+/+:fp16+ halve\n      #   memory at reduced precision, while +:fp32+/+:fp64+ keep higher precision.\n      # @return [Boolean, String] when +nx+ or +xx+ is given, +true+ on success and +false+\n      #   when the condition was not met; otherwise the raw +\"OK\"+ reply\n      # @raise [ArgumentError] if both +nx+ and +xx+ are given (they are mutually exclusive),\n      #   or if +fpha+ is not one of the supported types\n      # @raise [Redis::CommandError] if a value in the array does not fit the chosen\n      #   +fpha+ type (\"value out of range for ...\")\n      def json_set(key, path, value, nx: false, xx: false, raw: false, fpha: nil)\n        raise ArgumentError, \"nx and xx are mutually exclusive\" if nx && xx\n\n        if fpha\n          fpha = fpha.to_s.upcase\n          unless JSON_SET_FPHA_TYPES.include?(fpha)\n            raise ArgumentError, \"fpha accepts only: #{JSON_SET_FPHA_TYPES.join(', ')}\"\n          end\n        end\n\n        value = ::JSON.generate(value) unless raw\n        args = [:\"JSON.SET\", key, path, value]\n        args << \"NX\" if nx\n        args << \"XX\" if xx\n        args << \"FPHA\" << fpha if fpha\n\n        if nx || xx\n          send_command(args, &BoolifySet)\n        else\n          send_command(args)","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/redis/redis-rb/blob/2ba9010b91dab9e0fde1fbae3a9aae003f8bc307/lib/redis/commands/modules/json.rb#L77-L113","documentation":"Raised by redis-rb before anything reaches the server. JSON.SET supports two mutually exclusive conditional-write modes: nx (set only when the path does not exist) and xx (set only when it does). Passing both at once is contradictory, so json_set raises ArgumentError immediately at lib/redis/commands/modules/json.rb:95 instead of sending an invalid command. This mirrors the plain SET command, where NX and XX together are also a syntax error.","triggerScenarios":"redis.json_set(key, path, value, nx: true, xx: true); building flags from request params where both end up truthy, e.g. json_set(k, p, v, nx: params[:create], xx: params[:update]) with both present.","commonSituations":"Upsert helpers copied from code that used SET nx/xx; option hashes merged from defaults plus user overrides; porting from clients where the later flag silently wins, so authors expect the same behavior here.","solutions":["Pass exactly one of nx: true or xx: true, or neither for an unconditional set","When flags come from user input, resolve them to a single mode symbol first (nil, :nx, or :xx) and branch on it","Add a guard in your wrapper that raises a clear config error if both flags are set"],"exampleFix":"// before\nredis.json_set(\"doc\", \"$.a\", 1, nx: true, xx: true)\n// after\nredis.json_set(\"doc\", \"$.a\", 1, xx: true) # or nx: true, never both","handlingStrategy":"validation","validationCode":"def json_write(redis, key, path, value, mode: nil)\n  unless [nil, :nx, :xx].include?(mode)\n    raise ArgumentError, \"mode must be nil, :nx or :xx\"\n  end\n  redis.json_set(key, path, value, **(mode ? { mode => true } : {}))\nend","typeGuard":"mode.nil? || %i[nx xx].include?(mode)","tryCatchPattern":"begin\n  redis.json_set(k, p, v, **flags)\nrescue ArgumentError => e\n  raise ConfigError, \"json_set flags invalid: #{e.message}\"\nend","preventionTips":["Model the conditional mode as one symbol (:nx or :xx) instead of two booleans","Never spread an unfiltered params hash into json_set kwargs","Assert at most one of nx/xx in wrappers that forward options"],"tags":["redis-json","argumenterror","nx-xx","client-side-validation","upsert"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"2ba9010b91dab9e0fde1fbae3a9aae003f8bc307","analyzedAt":"2026-08-23T03:54:57.017Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}