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

  1. Set a DN format template in properties, e.g. cas.authn.ldap[0].dn-format=uid=%s,ou=people,dc=example,dc=org
  2. Verify the property actually resolves (check property source precedence, profile-specific overrides) so it is not blank at runtime
  3. 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

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.

Related errors


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)