apereo/cas · error · IllegalArgumentException
Dn format cannot be empty/blank for authentication
Error message
Dn format cannot be empty/blank for authentication
What it means
CAS's LdapUtils builds an LDAP authenticator from `cas.authn.ldap[*].dn-format`; the DN format template is what ldaptive uses to turn a submitted username into an entry DN. When `getDnFormatAuthenticator` finds the configured dnFormat blank, no DN can ever be formed, so it fails fast with this IllegalArgumentException during authenticator construction at startup/configuration refresh.
Solutions
- Set a DN format template in properties, e.g. cas.authn.ldap[0].dn-format=uid=%s,ou=people,dc=example,dc=org
- Verify the property actually resolves (check property source precedence, profile-specific overrides) so it is not blank at runtime
- If your directory cannot use a single DN template, switch to search-bind mode by setting base-dn plus search-filter instead of dn-format
Example fix
// before cas.authn.ldap[0].type=DIRECT cas.authn.ldap[0].dn-format= // after cas.authn.ldap[0].type=DIRECT cas.authn.ldap[0].dn-format=uid=%s,ou=people,dc=example,dc=org
Defensive patterns
Strategy: validation
Validate before calling
if (StringUtils.isBlank(casProperties.getAuthn().getLdap().get(0).getDnFormat())) {
throw new IllegalStateException("cas.authn.ldap[0].dn-format must be set for direct bind");
} Try / catch
try {
authenticator = LdapUtils.newLdaptiveAuthenticator(props);
} catch (IllegalArgumentException e) {
logger.error("LDAP dn-format misconfigured: {}", e.getMessage());
throw e; // fail fast at startup
} Prevention
- Always set dn-format when using DIRECT bind type; use base-dn + search-filter when using SEARCH bind
- Add a startup smoke test that constructs all configured authenticators
- Keep LDAP settings in one reviewed profile-specific file to avoid blank overrides
When it happens
Trigger: Configuring an LDAP authentication handler with direct bind (search-less) mode but leaving `cas.authn.ldap[...].dn-format` empty, whitespace-only, or undefined; the error is raised when newLdaptiveAuthenticator calls getDnFormatAuthenticator.
Common situations: Copy-pasting LDAP config samples without setting dn-format; switching from search-bind mode (where dn-format is unused) to direct bind and forgetting to add it; YAML/properties typos leaving the key empty; templated config where a placeholder like ${dnFormat} resolves to empty.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Principal id attribute is not found for [principalAttr]
- Multiple principal values are not allowed: [principalAttr]
- Could not locate an LDAP entry for [filter] and base DN…
- LDAP url cannot be empty/blank
- Base dn cannot be empty/blank for authenticated/anonymous…
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/64a7d0b7536b063b.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-ldap-core/src/main/java/org/apereo/cas/util/LdapUtils.java:805
if (StringUtils.isBlank(properties.getSearchFilter())) {
throw new IllegalArgumentException("User filter cannot be empty/blank for authenticated/anonymous authentication");
}
val connectionFactory = newLdaptiveConnectionFactory(properties);
val resolver = buildAggregateDnResolver(properties, connectionFactory);
val auth = StringUtils.isBlank(properties.getPrincipalAttributePassword())
? new Authenticator(resolver, getBindAuthenticationHandler(connectionFactory))
: new Authenticator(resolver, getCompareAuthenticationHandler(properties, connectionFactory));
if (properties.isEnhanceWithEntryResolver()) {
auth.setEntryResolver(newLdaptiveSearchEntryResolver(properties, connectionFactory));
}
return auth;
}
private static Authenticator getDnFormatAuthenticator(final AbstractLdapAuthenticationProperties properties) {
if (StringUtils.isBlank(properties.getDnFormat())) {
throw new IllegalArgumentException("Dn format cannot be empty/blank for authentication");
}
return getAuthenticatorViaDnFormat(properties, newLdaptiveConnectionFactory(properties));
}
private static Authenticator getAuthenticatorViaDnFormat(final AbstractLdapAuthenticationProperties properties,
final ConnectionFactory factory) {
val resolver = new FormatDnResolver(properties.getDnFormat());
val authenticator = new Authenticator(resolver, getBindAuthenticationHandler(factory));
if (properties.isEnhanceWithEntryResolver()) {
authenticator.setEntryResolver(newLdaptiveSearchEntryResolver(properties, factory));
}
return authenticator;
}
private static AuthenticationHandler getBindAuthenticationHandler(final ConnectionFactory factory) {
return new SimpleBindAuthenticationHandler(factory);
}View on GitHub (pinned to e7288fc434)