apereo/cas · error · LoginException
Multiple principal values are not allowed: [principalAttr]
Error message
Multiple principal values are not allowed: [principalAttr]
What it means
LdapAuthenticationHandler reads the principal id attribute from the LDAP entry returned by bind/search. If the attribute holds more than one value and allowMultiplePrincipalAttributeValues is false (the default), the handler aborts the login with a LoginException rather than guess which value identifies the principal.
Solutions
- Set cas.authn.ldap[x].allow-multiple-principal-attribute-values=true so the first value is used with a warning
- Clean the directory entry so the principal id attribute has exactly one value
- Point principalIdAttribute at an attribute guaranteed single-valued (e.g. uid, sAMAccountName, entryUUID)
- Add the search filter a constraint (or refine base DN) so only entries with a single value match
Example fix
// before (application.yml) cas.authn.ldap[0].principal-attribute-list=mail // after cas.authn.ldap[0].principal-attribute-list=mail cas.authn.ldap[0].allow-multiple-principal-attribute-values=true
Defensive patterns
Strategy: validation
Validate before calling
// in directory management / before enabling handler
String filter = "(uid=" + username + ")";
SearchResult entry = LdapUtils.searchForEntry(props, filter);
Attribute attr = entry.getAttribute(principalIdAttr);
if (attr != null && attr.size() > 1) {
throw new IllegalStateException("Principal id attribute is multivalued for " + username);
} Try / catch
try {
handler.authenticate(transaction);
} catch (LoginException e) {
if (e.getMessage().startsWith("Multiple principal values are not allowed")) {
// flag entry for directory cleanup or enable allow-multiple-principal-attribute-values
}
} Prevention
- Only choose single-valued attributes (uid, entryUUID, sAMAccountName) as principalIdAttribute
- Run a directory audit for multivalued attributes before enabling strict checking
- Enable allow-multiple-principal-attribute-values in environments known to have duplicate values
- Monitor the WARN log "Found multiple values for principal id attribute"
When it happens
Trigger: Configured principalIdAttribute (e.g. uid, mail) is multivalued in the directory for the authenticating user — common with mail, memberOf-style attributes, or entries that merged two records — while cas.authn.ldap[x].allow-multiple-principal-attribute-values is not enabled.
Common situations: Directory cleanup after org merges leaves a user with two mail values; admin points principalIdAttribute at a multivalued attribute like mail or employeeType; upgrading CAS to a stricter handler version surfaces previously hidden duplicate values.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Authentication has failed because LDAP password policy…
- No user can be accepted because none is defined
- Invalid credentials
- Principal id attribute is not found for [principalAttr]
- Could not locate an LDAP entry for [filter] and base DN…
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/270e54c9a37a5b0c.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-ldap-core/src/main/java/org/apereo/cas/authentication/LdapAuthenticationHandler.java:213
if (StringUtils.isNotBlank(this.principalIdAttribute)) {
val principalAttr = ldapEntry.getAttribute(this.principalIdAttribute);
if (principalAttr == null || principalAttr.size() == 0) {
if (this.allowMissingPrincipalAttributeValue) {
LOGGER.warn("The principal id attribute [{}] is not found. CAS cannot construct the final authenticated principal "
+ "if it's unable to locate the attribute that is designated as the principal id. "
+ "Attributes available on the LDAP entry are [{}]. Since principal id attribute is not available, CAS will "
+ "fall back to construct the principal based on the provided user id: [{}]",
this.principalIdAttribute, ldapEntry.getAttributes(), username);
return username;
}
LOGGER.error("The principal id attribute [{}] is not found. CAS is configured to disallow missing principal attributes",
this.principalIdAttribute);
throw new LoginException("Principal id attribute is not found for " + principalAttr);
}
val value = principalAttr.getStringValue();
if (principalAttr.size() > 1) {
if (!this.allowMultiplePrincipalAttributeValues) {
throw new LoginException("Multiple principal values are not allowed: " + principalAttr);
}
LOGGER.warn("Found multiple values for principal id attribute: [{}]. Using first value=[{}].", principalAttr, value);
}
LOGGER.debug("Retrieved principal id attribute [{}]", value);
return value;
}
LOGGER.debug("Principal id attribute is not defined. Using the default provided user id [{}]", username);
return username;
}
private AuthenticationResponse getLdapAuthenticationResponse(final UsernamePasswordCredential upc) throws PreventedException {
try {
LOGGER.debug("Attempting LDAP authentication for [{}]. Authenticator pre-configured attributes are [{}], "
+ "additional requested attributes for this authentication request are [{}]", upc, authenticator.getReturnAttributes(),
authenticatedEntryAttributes);
var ldaptiveCred = new Credential(upc.getPassword());
val request = new AuthenticationRequest(upc.getUsername(), ldaptiveCred, authenticatedEntryAttributes);
request.setControls(new PasswordPolicyControl());View on GitHub (pinned to e7288fc434)