apereo/cas · warning
Email address [ ] for [ ] is not valid
Error message
Email address [{}] for [{}] is not valid What it means
LdapPasswordManagementService.findEmails reads the configured mail attribute for the user from LDAP and validates it with commons-validator's EmailValidator. If the stored value fails validation the warn is logged and an empty set is returned, which downstream causes the reset flow to report 'no recipient'.
Solutions
- Inspect the user's LDAP entry value for the mail attribute and correct it to a valid single RFC-822 address
- Point cas.authn.pm.reset.mail.attributeName at the attribute that actually holds a valid email
- Use a multivalued-aware mapping/objectClass so only a proper mail attribute is returned
- If the address format is legitimately unusual, normalize it in the directory or use a custom PasswordManagementService
Example fix
// before cas.authn.pm.reset.mail.attributeName=mail // directory value: 'jsmith@example' (invalid) // after — fix LDAP entry or map the right attribute cas.authn.pm.reset.mail.attributeName=mail // directory value: 'jsmith@example.com' (valid)
Defensive patterns
Strategy: validation
Validate before calling
String email = ldapMailAttribute;
if (email == null || !org.apache.commons.validator.routines.EmailValidator.getInstance().isValid(email)) {
log.warn("Refusing reset: invalid email {}", email);
} Type guard
boolean isValidEmail(String v) {
return v != null && org.apache.commons.validator.routines.EmailValidator.getInstance().isValid(v.trim());
} Prevention
- Directory data hygiene: audit mail attributes for malformed/multivalued values
- Map the PM mail attribute to a field guaranteed to hold one RFC-822 address
- Add a periodic report of entries whose mail attribute fails validation
When it happens
Trigger: findAttribute returned a value for cas.authn.pm.reset.mail.attributeName, but EmailValidator.getInstance().isValid(email) is false — e.g. malformed address, multiple/blank values, or a placeholder string.
Common situations: LDAP mail attribute contains a list or concatenated values; entry has 'user@example' or empty string; attribute mapped to the wrong LDAP field (e.g. uid); trailing spaces or non-ASCII data in the attribute.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Could not locate LDAP attribute
- Invalid credentials
- [username] not found.
- Principal id attribute is not found for [principalAttr]
- Multiple principal values are not allowed: [principalAttr]
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/a75e12f2b3ff681c.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-pm-ldap/src/main/java/org/apereo/cas/pm/LdapPasswordManagementService.java:58
super(casProperties, cipherExecutor, passwordHistoryService);
this.connectionFactoryMap = Map.copyOf(connectionFactoryMap);
}
@Override
public void destroy() {
this.connectionFactoryMap.forEach((ldap, connectionFactory) ->
connectionFactory.close());
}
@Override
public Set<String> findEmails(final PasswordManagementQuery query) {
val email = findAttribute(query, casProperties.getAuthn().getPm().getReset().getMail().getAttributeName(),
CollectionUtils.wrap(query.getUsername()));
if (EmailValidator.getInstance().isValid(email)) {
LOGGER.debug("Email address [{}] for [{}] appears valid", email, query.getUsername());
return Set.of(email);
}
LOGGER.warn("Email address [{}] for [{}] is not valid", email, query.getUsername());
return Set.of();
}
@Override
public String findPhone(final PasswordManagementQuery query) {
return findAttribute(query, casProperties.getAuthn().getPm().getReset().getSms().getAttributeName(), CollectionUtils.wrap(query.getUsername()));
}
@Override
public String findUsername(final PasswordManagementQuery query) {
return findAttribute(query, casProperties.getAuthn().getPm().getLdap().stream()
.map(LdapPasswordManagementProperties::getUsernameAttribute)
.collect(Collectors.toList()), CollectionUtils.wrap(query.getEmail()));
}
@Override
public void updateSecurityQuestions(final PasswordManagementQuery query) {
findEntries(CollectionUtils.wrap(query.getUsername()), true)View on GitHub (pinned to e7288fc434)