{"record":{"id":"e26819aa3141dff6","repo":"quarkusio/quarkus","slug":"cannot-set-xx-and-nx-together","errorCode":null,"errorMessage":"Cannot set XX and NX together","messagePattern":"Cannot set XX and NX together","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/geo/GeoAddArgs.java","lineNumber":47,"sourceCode":"    public GeoAddArgs xx() {\n        this.xx = true;\n        return this;\n    }\n\n    /**\n     * Modify the return value from the number of new elements added, to the total number of elements changed.\n     * (CH is an abbreviation of changed).\n     *\n     * @return the current {@code GeoaddArgs}\n     **/\n    public GeoAddArgs ch() {\n        this.ch = true;\n        return this;\n    }\n\n    public List<Object> toArgs() {\n        if (xx && nx) {\n            throw new IllegalArgumentException(\"Cannot set XX and NX together\");\n        }\n        List<Object> args = new ArrayList<>();\n        if (xx) {\n            args.add(\"XX\");\n        }\n        if (nx) {\n            args.add(\"NX\");\n        }\n        if (ch) {\n            args.add(\"CH\");\n        }\n        return args;\n    }\n}\n","sourceCodeStart":29,"sourceCodeEnd":62,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/geo/GeoAddArgs.java#L29-L62","documentation":"GeoAddArgs.toArgs() serializes GEOADD options and enforces Redis's rule that XX (only update existing members) and NX (only add new members) are mutually exclusive. Setting both flags on the same GeoAddArgs throws this IllegalArgumentException when the command is built by cmd().","triggerScenarios":"Calling geoAddArgs.xx().nx() (or the chained equivalents) on the same args object before passing it to geoadd(); also when flags are set conditionally from two different config flags that happen to both be true.","commonSituations":"Copying a fluent chain and leaving both xx() and nx() in it; combining two feature flags (updateExisting + addNewOnly) that can both be enabled in config; merging args objects built in different code paths.","solutions":["Choose one: use xx() to only update existing members, or nx() to only add new ones — not both.","If flags come from config, validate that at most one is true and pick a precedence before building args.","Remove the redundant flag call from the fluent chain."],"exampleFix":"// before\nGeoAddArgs args = GeoAddArgs.Builder.geoAddArgs().xx().nx(); // throws in toArgs\n// after\nGeoAddArgs args = updateExisting ? GeoAddArgs.Builder.geoAddArgs().xx() : GeoAddArgs.Builder.geoAddArgs().nx();","handlingStrategy":"validation","validationCode":"if (updateExisting && onlyAddNew) {\n    throw new IllegalArgumentException(\"GEOADD XX and NX are mutually exclusive; pick one\");\n}\nGeoAddArgs a = GeoAddArgs.Builder.geoAddArgs();\nif (updateExisting) a.xx(); else if (onlyAddNew) a.nx();","typeGuard":null,"tryCatchPattern":"try { return geo.geoadd(args, members); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"XX and NX\")) { args = GeoAddArgs.Builder.geoAddArgs().nx(); return geo.geoadd(args, members); } throw e; }","preventionTips":["Never chain .xx() and .nx() on the same GeoAddArgs.","If driven by config flags, enforce mutual exclusivity at config validation time.","Decide precedence (update wins vs add wins) once and encode it in a helper method."],"tags":["redis","geo","mutually-exclusive-options"],"backgroundTag":"conflicting-options","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}