{"record":{"id":"2164760617235756","repo":"apache/cassandra","slug":"only-one-of-s-s-can-be-specified","errorCode":null,"errorMessage":"Only one of %s, %s can be specified.","messagePattern":"Only one of (.+?), (.+?) can be specified\\.","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/auth/PasswordDefaultRoleInitializer.java","lineNumber":118,"sourceCode":"    @Override\n    public String defaultRoleName()\n    {\n        return role;\n    }\n\n    @Override\n    public void validateConfiguration() throws ConfigurationException\n    {\n        if (Strings.isNullOrEmpty(role))\n            throw new ConfigurationException(String.format(\"%s requires a non-empty %s parameter\", getClass().getSimpleName(), ROLE));\n\n        boolean specifiedPassword = !Strings.isNullOrEmpty(password);\n        boolean specifiedPasswordHash = !Strings.isNullOrEmpty(passwordHash);\n\n        if (!specifiedPassword && !specifiedPasswordHash)\n            throw new ConfigurationException(String.format(\"There has to be one of %s, %s specified.\", PASSWORD, PASSWORD_HASH));\n        else if (specifiedPassword && specifiedPasswordHash)\n            throw new ConfigurationException(String.format(\"Only one of %s, %s can be specified.\", PASSWORD, PASSWORD_HASH));\n    }\n\n    @VisibleForTesting\n    public String createDefaultRoleQuery()\n    {\n        return String.format(\"INSERT INTO %s.%s (role, is_superuser, can_login, salted_hash) VALUES ('%s', true, true, '%s') USING TIMESTAMP 0\",\n                             SchemaConstants.AUTH_KEYSPACE_NAME,\n                             AuthKeyspace.ROLES,\n                             escapeCqlLiteral(role),\n                             escapeCqlLiteral(password == null ? passwordHash : hashpw(password)));\n    }\n}\n","sourceCodeStart":100,"sourceCodeEnd":131,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/auth/PasswordDefaultRoleInitializer.java#L100-L131","documentation":"The default role may be seeded from exactly one secret source. validateConfiguration() rejects configurations that specify both plaintext password and password_hash, since they are mutually exclusive and ambiguous (which one is authoritative?).","triggerScenarios":"cassandra.yaml default role options containing both password and password_hash keys with non-empty values.","commonSituations":"Merging yaml fragments where one file sets password and another sets password_hash; migrating from plaintext to hashed secrets without deleting the old key; automation templates writing both fields.","solutions":["Remove the password key and keep only password_hash (preferred, avoids plaintext in yaml)","Or remove password_hash and keep only password","Keep a single canonical source for the secret in your config management to avoid re-introducing the conflict"],"exampleFix":"// before\nrole_name: cassandra\npassword: ChangeMeNow\npassword_hash: $2a$10$...\n// after\nrole_name: cassandra\npassword_hash: $2a$10$...","handlingStrategy":"validation","validationCode":"if (notBlank(password) && notBlank(passwordHash)) fail(\"password and password_hash are mutually exclusive\");","typeGuard":"boolean exactlyOneSecret(Map<String,String> o) { int n = (notBlank(o.get(\"password\"))?1:0) + (notBlank(o.get(\"password_hash\"))?1:0); return n == 1; }","tryCatchPattern":"try { config.validate(); } catch (ConfigurationException e) { if (e.getMessage().startsWith(\"Only one of\")) dropPlaintextField(); }","preventionTips":["Model the two fields as a single choice (oneOf) in config tooling","When migrating to password_hash, delete the password key in the same change","Add a lint rule for cassandra.yaml rejecting both keys together"],"tags":["configuration","auth","conflicting-options"],"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"}