apereo/cas · error · IllegalArgumentException

User filter cannot be empty/blank for…

Error message

User filter cannot be empty/blank for authenticated/anonymous authentication

What it means

Immediately after validating baseDn, getAuthenticatedOrAnonSearchAuthenticator requires a non-blank searchFilter (user filter) because the search-and-bind Authenticator needs a filter to locate the user entry. A blank filter triggers IllegalArgumentException.

Solutions

  1. Set cas.authn.ldap[x].search-filter to a valid filter, e.g. (uid={user}) or (sAMAccountName={user})
  2. Confirm the filter is in the same ldap[x] block as the other authentication settings
  3. Match the filter attribute to your directory's naming attribute

Example fix

// before
cas.authn.ldap[0].search-filter=
// after
cas.authn.ldap[0].search-filter=(sAMAccountName={user})
Defensive patterns

Strategy: validation

Validate before calling

if (props.getSearchFilter() == null || props.getSearchFilter().isBlank()) {
    throw new IllegalStateException("search-filter is required for authenticated/anonymous LDAP search");
}

Try / catch

try {
    Authenticator a = LdapUtils.newLdaptiveAuthenticator(props);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("User filter cannot be empty/blank")) {
        // abort wiring and report the missing search-filter config
    }
}

Prevention

When it happens

Trigger: Authenticated/anonymous search configuration where cas.authn.ldap[x].search-filter (user-filter) is missing or empty when newLdaptiveAuthenticator builds the authenticator.

Common situations: Template-based config with search-filter commented out; assuming a default filter exists when none is applied; filter moved to the wrong config block after refactoring; programmatic AbstractLdapAuthenticationProperties built without setSearchFilter.

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/ff13958f631d8de8. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-ldap-core/src/main/java/org/apereo/cas/util/LdapUtils.java:788

                }
                default -> searchResultHandlers.add(new MergeResultHandler());
            }
        });
        return searchResultHandlers;
    }

    /**
     * Gets authenticated authenticator.
     *
     * @param properties the lDAP properties
     * @return the authenticated or anon search authenticator
     */
    public static Authenticator getAuthenticatedOrAnonSearchAuthenticator(final AbstractLdapAuthenticationProperties properties) {
        if (StringUtils.isBlank(properties.getBaseDn())) {
            throw new IllegalArgumentException("Base dn cannot be empty/blank for authenticated/anonymous authentication");
        }
        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");
        }

View on GitHub (pinned to e7288fc434)