{"record":{"id":"a4d46fc7f8b56e88","repo":"apache/cassandra","slug":"properties-s-and-s-are-mutually-exclusive","errorCode":null,"errorMessage":"Properties '%s' and '%s' are mutually exclusive","messagePattern":"Properties '(.+?)' and '(.+?)' are mutually exclusive","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/auth/RoleOptions.java","lineNumber":158,"sourceCode":"                throw new InvalidRequestException(String.format(\"%s doesn't support %s\",\n                                                                DatabaseDescriptor.getRoleManager().getClass().getName(),\n                                                                option.getKey()));\n            switch (option.getKey())\n            {\n                case LOGIN:\n                case SUPERUSER:\n                    if (!(option.getValue() instanceof Boolean))\n                        throw new InvalidRequestException(String.format(\"Invalid value for property '%s'. \" +\n                                                                        \"It must be a boolean\",\n                                                                        option.getKey()));\n                    break;\n                case PASSWORD:\n                    if (!(option.getValue() instanceof String))\n                        throw new InvalidRequestException(String.format(\"Invalid value for property '%s'. \" +\n                                                                        \"It must be a string\",\n                                                                        option.getKey()));\n                    if (options.containsKey(IRoleManager.Option.HASHED_PASSWORD))\n                        throw new InvalidRequestException(String.format(\"Properties '%s' and '%s' are mutually exclusive\",\n                                                                        IRoleManager.Option.PASSWORD, IRoleManager.Option.HASHED_PASSWORD));\n                    break;\n                case HASHED_PASSWORD:\n                    if (!(option.getValue() instanceof String))\n                        throw new InvalidRequestException(String.format(\"Invalid value for property '%s'. \" +\n                                                                        \"It must be a string\",\n                                                                        option.getKey()));\n                    if (options.containsKey(IRoleManager.Option.PASSWORD))\n                        throw new InvalidRequestException(String.format(\"Properties '%s' and '%s' are mutually exclusive\",\n                                                                        IRoleManager.Option.PASSWORD, IRoleManager.Option.HASHED_PASSWORD));\n                    try\n                    {\n                        BCrypt.checkpw(\"dummy\", (String) option.getValue());\n                    }\n                    catch (Exception e)\n                    {\n                        throw new InvalidRequestException(\"Invalid hashed password value. Please use jBcrypt.\");\n                    }","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/auth/RoleOptions.java#L140-L176","documentation":"A role cannot have both PASSWORD and HASHED_PASSWORD set: PASSWORD would be hashed by Cassandra while HASHED_PASSWORD supplies an already-hashed value (e.g. bcrypt). RoleOptions.validate() throws InvalidRequestException when PASSWORD is present and HASHED_PASSWORD is also in the options map.","triggerScenarios":"CREATE ROLE/ALTER ROLE statement including both WITH PASSWORD = 'x' AND HASHED_PASSWORD = '$2a$...'.","commonSituations":"Migration scripts that include both plaintext and pre-hashed credentials; tools that merge default options with user-supplied options and accidentally combine both keys.","solutions":["Provide only PASSWORD (plaintext, hashed by the server) or only HASHED_PASSWORD (pre-hashed bcrypt), not both.","If the password is already hashed, drop the PASSWORD option.","Fix automation that merges both option keys into one statement."],"exampleFix":"// before\nCREATE ROLE alice WITH PASSWORD = 'secret' AND HASHED_PASSWORD = '$2a$10$...';\n// after\nCREATE ROLE alice WITH HASHED_PASSWORD = '$2a$10$...';","handlingStrategy":"validation","validationCode":"if (roleOptions.containsKey(IRoleManager.Option.PASSWORD)\n    && roleOptions.containsKey(IRoleManager.Option.HASHED_PASSWORD))\n    throw new IllegalArgumentException(\"Provide either PASSWORD or HASHED_PASSWORD, not both\");","typeGuard":null,"tryCatchPattern":"try {\n    roleOptions.validate();\n} catch (InvalidRequestException e) {\n    if (e.getMessage().contains(\"mutually exclusive\")) {\n        // drop one credential option and retry\n    }\n}","preventionTips":["Decide on one credential form (plaintext or pre-hashed) per workflow.","Validate merged option maps before issuing CREATE/ALTER ROLE.","In migrations, strip default PASSWORD when supplying HASHED_PASSWORD."],"tags":["cassandra","auth","roles","conflict"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}