apereo/cas · warning

Principal resolution is set to resolve users via…

Error message

Principal resolution is set to resolve users via attribute(s) [{}], and yet the collection of attributes retrieved [{}] do not contain any of those attributes. This is likely due to misconfiguration and CAS will use [{}] as the final principal id

What it means

During principal construction CAS was configured to derive the principal id from specific attributes (principalAttributeNames), but none of those attributes were present in the attribute bundle retrieved from the attribute repository. CAS falls back to the default principal id (usually the username) and marks the resolution as a non-success. This warn signals that the attribute-source configuration and the principalAttributeNames setting disagree.

Solutions

  1. Check cas.authn.attributeRepository.core.principalAttributeNames and verify each name exists exactly (case included) in the attributes returned by your attribute repository
  2. Enable debug logging for org.apereo.cas.authentication.principal.resolvers to inspect the actual retrieved attribute keys
  3. Correct the LDAP/attribute-repository filter or returned attributes so the desired attribute is fetched
  4. Remove the principalAttributeNames setting if falling back to the username is actually desired

Example fix

// before
cas.authn.attributeRepository.core.principalAttributeNames=mail
// (directory returns 'emailAddress')
// after
cas.authn.attributeRepository.core.principalAttributeNames=emailAddress
Defensive patterns

Strategy: validation

Validate before calling

// before CAS startup, assert configured principal attributes exist in the repository output
Set<String> attrs = principalAttributes.keySet();
List<String> configured = List.of("mail"); // cas.authn...principalAttributeNames
if (configured.stream().noneMatch(attrs::contains)) {
    throw new IllegalStateException("None of " + configured + " present in " + attrs);
}

Type guard

boolean hasPrincipalAttribute(Map<String,Object> attrs, List<String> names) {
    return names != null && names.stream().anyMatch(n -> attrs.containsKey(n.trim()));
}

Prevention

When it happens

Trigger: PersonDirectoryPrincipalResolver.convertPersonAttributesToPrincipal is invoked with context.getPrincipalAttributeNames() set (e.g. cas.authn.attributeRepository.core.principalAttributeNames=mail), but the resolved attribute map contains no key matching any of those names after trimming.

Common situations: LDAP attribute renamed (mail vs emailAddress); attribute not requested/released by the attribute repository; case-sensitivity mismatch in attribute names; user record simply lacks the attribute; principalAttributeNames left over from a copied config for a different directory schema.

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


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/c9e88ab5723f7b55. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-person-directory-core/src/main/java/org/apereo/cas/authentication/principal/resolvers/PersonDirectoryPrincipalResolver.java:151

            val attrNames = org.springframework.util.StringUtils.commaDelimitedListToSet(context.getPrincipalAttributeNames());

            val principalIdAttributes = new LinkedHashMap<>(attributes);
            if (context.isUseCurrentPrincipalId() && currentPrincipal.isPresent()) {
                val currentPrincipalAttributes = currentPrincipal.get().getAttributes();
                LOGGER.trace("Merging current principal attributes [{}] with resolved attributes [{}]",
                    currentPrincipalAttributes, principalIdAttributes);
                context.getAttributeMerger().mergeAttributes(principalIdAttributes, currentPrincipalAttributes);
            }

            LOGGER.debug("Using principal attributes [{}] to determine principal id", principalIdAttributes);
            val result = attrNames.stream()
                .map(String::trim)
                .filter(principalIdAttributes::containsKey)
                .map(principalIdAttributes::get)
                .findFirst();

            if (result.isEmpty()) {
                LOGGER.warn("Principal resolution is set to resolve users via attribute(s) [{}], and yet "
                        + "the collection of attributes retrieved [{}] do not contain any of those attributes. This is "
                        + "likely due to misconfiguration and CAS will use [{}] as the final principal id",
                    context.getPrincipalAttributeNames(), principalIdAttributes.keySet(), principalId);
                builder.success(false);
            } else {
                val values = result.get();
                if (!values.isEmpty()) {
                    principalId = CollectionUtils.firstElement(values).map(Object::toString).orElseThrow();
                    LOGGER.debug("Found principal id attribute value [{}]", principalId);
                }
            }
        }
        return builder.principalId(principalId).attributes(convertedAttributes).build();
    }

    protected Map<String, List<Object>> retrievePersonAttributes(final String principalId,
                                                                 final Credential credential,
                                                                 final Optional<Principal> currentPrincipal,

View on GitHub (pinned to e7288fc434)