apache/cassandra · error · ConfigurationException

There has to be one of

Error message

There has to be one of %s, %s specified.

What it means

validateConfiguration() requires the default role to be seeded with a secret: either a plaintext password or a pre-computed salted hash must be present. If neither is specified, ConfigurationException is thrown because the created role would be unusable/unloggable.

Solutions

  1. Add password: <plaintext> to the default role options in cassandra.yaml
  2. Or supply password_hash: <bcrypt hash> to avoid storing plaintext in the yaml
  3. Re-run startup config validation after the change to confirm

Example fix

// before
role_name: cassandra
// after
role_name: cassandra
password_hash: $2a$10$...
Defensive patterns

Strategy: validation

Validate before calling

if (isBlank(password) && isBlank(passwordHash)) fail("set either password or password_hash for the default role");

Type guard

boolean hasSecret(Map<String,String> opts) { return notBlank(opts.get("password")) || notBlank(opts.get("password_hash")); }

Try / catch

try { config.validate(); } catch (ConfigurationException e) { promptForDefaultRolePassword(); }

Prevention

When it happens

Trigger: cassandra.yaml default role options set with role_name but neither password nor password_hash provided (both null/empty).

Common situations: Operators filling in role_name but forgetting the password; config generators dropping secret values from unmanaged keys; copy-pasting a partial example config.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/auth/PasswordDefaultRoleInitializer.java:116

    }

    @Override
    public String defaultRoleName()
    {
        return role;
    }

    @Override
    public void validateConfiguration() throws ConfigurationException
    {
        if (Strings.isNullOrEmpty(role))
            throw new ConfigurationException(String.format("%s requires a non-empty %s parameter", getClass().getSimpleName(), ROLE));

        boolean specifiedPassword = !Strings.isNullOrEmpty(password);
        boolean specifiedPasswordHash = !Strings.isNullOrEmpty(passwordHash);

        if (!specifiedPassword && !specifiedPasswordHash)
            throw new ConfigurationException(String.format("There has to be one of %s, %s specified.", PASSWORD, PASSWORD_HASH));
        else if (specifiedPassword && specifiedPasswordHash)
            throw new ConfigurationException(String.format("Only one of %s, %s can be specified.", PASSWORD, PASSWORD_HASH));
    }

    @VisibleForTesting
    public String createDefaultRoleQuery()
    {
        return String.format("INSERT INTO %s.%s (role, is_superuser, can_login, salted_hash) VALUES ('%s', true, true, '%s') USING TIMESTAMP 0",
                             SchemaConstants.AUTH_KEYSPACE_NAME,
                             AuthKeyspace.ROLES,
                             escapeCqlLiteral(role),
                             escapeCqlLiteral(password == null ? passwordHash : hashpw(password)));
    }
}

View on GitHub (pinned to 88fd0f6a0e)