apache/cassandra · error · InvalidRequestException

Properties '%s' and '%s' are mutually exclusive

Error message

Properties '%s' and '%s' are mutually exclusive

What it means

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.

Source

Thrown at src/java/org/apache/cassandra/auth/RoleOptions.java:158

                throw new InvalidRequestException(String.format("%s doesn't support %s",
                                                                DatabaseDescriptor.getRoleManager().getClass().getName(),
                                                                option.getKey()));
            switch (option.getKey())
            {
                case LOGIN:
                case SUPERUSER:
                    if (!(option.getValue() instanceof Boolean))
                        throw new InvalidRequestException(String.format("Invalid value for property '%s'. " +
                                                                        "It must be a boolean",
                                                                        option.getKey()));
                    break;
                case PASSWORD:
                    if (!(option.getValue() instanceof String))
                        throw new InvalidRequestException(String.format("Invalid value for property '%s'. " +
                                                                        "It must be a string",
                                                                        option.getKey()));
                    if (options.containsKey(IRoleManager.Option.HASHED_PASSWORD))
                        throw new InvalidRequestException(String.format("Properties '%s' and '%s' are mutually exclusive",
                                                                        IRoleManager.Option.PASSWORD, IRoleManager.Option.HASHED_PASSWORD));
                    break;
                case HASHED_PASSWORD:
                    if (!(option.getValue() instanceof String))
                        throw new InvalidRequestException(String.format("Invalid value for property '%s'. " +
                                                                        "It must be a string",
                                                                        option.getKey()));
                    if (options.containsKey(IRoleManager.Option.PASSWORD))
                        throw new InvalidRequestException(String.format("Properties '%s' and '%s' are mutually exclusive",
                                                                        IRoleManager.Option.PASSWORD, IRoleManager.Option.HASHED_PASSWORD));
                    try
                    {
                        BCrypt.checkpw("dummy", (String) option.getValue());
                    }
                    catch (Exception e)
                    {
                        throw new InvalidRequestException("Invalid hashed password value. Please use jBcrypt.");
                    }

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Provide only PASSWORD (plaintext, hashed by the server) or only HASHED_PASSWORD (pre-hashed bcrypt), not both.
  2. If the password is already hashed, drop the PASSWORD option.
  3. Fix automation that merges both option keys into one statement.

Example fix

// before
CREATE ROLE alice WITH PASSWORD = 'secret' AND HASHED_PASSWORD = '$2a$10$...';
// after
CREATE ROLE alice WITH HASHED_PASSWORD = '$2a$10$...';
Defensive patterns

Strategy: validation

Validate before calling

if (roleOptions.containsKey(IRoleManager.Option.PASSWORD)
    && roleOptions.containsKey(IRoleManager.Option.HASHED_PASSWORD))
    throw new IllegalArgumentException("Provide either PASSWORD or HASHED_PASSWORD, not both");

Try / catch

try {
    roleOptions.validate();
} catch (InvalidRequestException e) {
    if (e.getMessage().contains("mutually exclusive")) {
        // drop one credential option and retry
    }
}

Prevention

When it happens

Trigger: CREATE ROLE/ALTER ROLE statement including both WITH PASSWORD = 'x' AND HASHED_PASSWORD = '$2a$...'.

Common situations: Migration scripts that include both plaintext and pre-hashed credentials; tools that merge default options with user-supplied options and accidentally combine both keys.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/a4d46fc7f8b56e88. Report an issue: GitHub.