apereo/cas · error · IllegalStateException
Principal attribute [
Error message
Principal attribute [
What it means
Thrown by JdbcAcceptableUsagePolicyRepository.determinePrincipalId when the configured cas.acceptable-usage-policy.jdbc.principal-id-column/attribute name does not exist among the authenticated principal's attributes. CAS uses this attribute to look up the AUP record keyed by an alternate principal identifier, so a missing attribute makes the mapping impossible. It surfaces as IllegalStateException from determinePrincipalId, invoked via principalId during AUP policy checks.
Solutions
- Verify the attribute name in cas.acceptable-usage-policy.jdbc.principal-id-attribute exactly matches an attribute the principal actually carries (check the attribute name and casing).
- Ensure the attribute is fetched and released: adjust the authentication/attribute repository source or service release policy so it appears on the principal before AUP evaluation.
- If the CAS principal id itself is the right key, remove/unset the principal-id-attribute so determinePrincipalId falls back to principal.getId().
- Log the full principal attribute map (or check the audit/inspektr logs) to see which attributes are actually available at AUP evaluation time.
Example fix
// before (application.properties) cas.acceptable-usage-policy.jdbc.principal-id-attribute=employeeid // after (attribute actually present on the principal) cas.acceptable-usage-policy.jdbc.principal-id-attribute=employeeId
Defensive patterns
Strategy: validation
Validate before calling
// before enabling AUP-JDBC, confirm the attribute reaches the principal
if (!principal.getAttributes().containsKey(configuredPrincipalIdAttribute)) {
throw new IllegalStateException("AUP principal-id attribute missing: " + configuredPrincipalIdAttribute);
} Prevention
- Assert the attribute exists on the principal in a startup/integration test before deploying the AUP-JDBC config.
- Keep attribute names exactly as produced by the principal factory; avoid case drift between config and source.
- If unsure, omit principal-id-attribute and rely on the default principal.getId().
When it happens
Trigger: cas.acceptable-usage-policy.jdbc.principal-id-attribute is set to a name (e.g. 'employeeId') that is absent from principal.getAttributes() at the time the AUP repository resolves the principal id — typically after login when the attribute was never released into the principal.
Common situations: Typo in the attribute name in cas.properties; the attribute resolution strategy (source attribute release policy, LDAP/attribute repository config) does not actually fetch or release that attribute; casing mismatch between configured name and the attribute produced by the principal factory.
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
- Unable to determine authentication from the request context
- [e.getMessage()]
- Password does not match value on record.
- Password has expired
- Account has been disabled
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/c131638ecf6e17a1.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-aup-jdbc/src/main/java/org/apereo/cas/aup/JdbcAcceptableUsagePolicyRepository.java:104
* @return the acceptable usage policy column name
*/
protected String getAcceptableUsagePolicyColumnName(final JdbcAcceptableUsagePolicyProperties jdbc) {
return StringUtils.defaultIfBlank(jdbc.getAupColumn(), aupProperties.getCore().getAupAttributeName()).trim();
}
/**
* Extracts principal ID from a principal attribute or the provided credentials.
*
* @param principal the principal
* @return the principal ID to update the AUP setting in the database for
*/
protected String determinePrincipalId(final Principal principal) {
if (StringUtils.isBlank(aupProperties.getJdbc().getPrincipalIdAttribute())) {
return principal.getId();
}
val pIdAttribName = aupProperties.getJdbc().getPrincipalIdAttribute();
if (!principal.getAttributes().containsKey(pIdAttribName)) {
throw new IllegalStateException("Principal attribute [" + pIdAttribName + "] cannot be found");
}
val pIdAttributeValue = principal.getAttributes().get(pIdAttribName);
val pIdAttributeValues = CollectionUtils.toCollection(pIdAttributeValue);
var principalId = StringUtils.EMPTY;
if (!pIdAttributeValues.isEmpty()) {
principalId = pIdAttributeValues.iterator().next().toString().trim();
}
if (pIdAttributeValues.size() > 1) {
LOGGER.warn("Principal attribute [{}] was found, but its value [{}] is multi-valued. "
+ "Proceeding with the first element [{}]", pIdAttribName, pIdAttributeValue, principalId);
}
if (principalId.isEmpty()) {
throw new IllegalStateException("Principal attribute [" + pIdAttribName + "] was found, but it is either empty"
+ " or multi-valued with an empty element");
}
return principalId;
}
}View on GitHub (pinned to e7288fc434)