apereo/cas · error · RuntimeException

Script cache manager unavailable to handle LDAP filter

Error message

Script cache manager unavailable to handle LDAP filter

What it means

LdapUtils.newLdaptiveSearchFilter supports LDAP filters defined as inline Groovy scripts; when the filter is a script, it requires a ScriptCacheManager to compile/cache it. If no script cache manager was provided (null), it fails fast with this RuntimeException rather than executing the script unfiltered.

Solutions

  1. Ensure the calling component passes its configured ScriptCacheManager into newLdaptiveSearchFilter
  2. Check that the relevant CAS auto-configuration wires the script cache manager bean for your LDAP settings
  3. Rewrite the search filter as a static/template filter (non-Groovy) if scripting is not needed
  4. Verify the Groovy/scripting module is on the classpath and the filter syntax really requires a script

Example fix

// before: scripted filter without cache manager
// search-filter=groovy{return 'uid=' + user}
// and newLdaptiveSearchFilter(query, null, ...)
// after: pass the manager
newLdaptiveSearchFilter(query, scriptCacheManager, params);
// or use a static filter
// search-filter=(uid={user})
Defensive patterns

Strategy: validation

Validate before calling

if (filterQuery != null && filterQuery.contains("groovy:")) {
    Objects.requireNonNull(scriptCacheManager, "Scripted LDAP filters require a ScriptCacheManager");
}

Try / catch

try {
    Filter f = LdapUtils.newLdaptiveSearchFilter(query, scriptCacheManager, params);
} catch (RuntimeException e) {
    if ("Script cache manager unavailable to handle LDAP filter".equals(e.getMessage())) {
        // fall back to a static filter or wire the script cache manager
    }
}

Prevention

When it happens

Trigger: Calling newLdaptiveSearchFilter(...) with a filter query that contains a Groovy script (scripted filter syntax) while passing null for the ScriptCacheManager argument.

Common situations: Using a scripted LDAP filter (e.g. with cas.authn.ldap[x].search-filter written as a Groovy script) but the calling configuration class was constructed without a scriptCacheManager bean; upgrading CAS and adding script-based filters without the script support module/wiring.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/2e57b2f73da41541. Report an issue: GitHub.

Appendix: source

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

                                val scriptFactory = ExecutableCompiledScriptFactory.getExecutableCompiledScriptFactory();
                                script = scriptFactory.fromResource(resource);
                                cacheMgr.put(cacheKey, script);
                                LOGGER.trace("Cached groovy script [{}] for key [{}]", script, cacheKey);
                            }
                            if (script != null) {
                                val parameters = IntStream.range(0, values.size())
                                    .boxed()
                                    .collect(Collectors.toMap(paramName::get, values::get, (a, b) -> b, LinkedHashMap::new));
                                val args = CollectionUtils.<String, Object>wrap("filter", filter,
                                    "parameters", parameters,
                                    "applicationContext", ApplicationContextProvider.getApplicationContext(),
                                    "logger", LOGGER);
                                script.setBinding(args);
                                script.execute(args.values().toArray(), FilterTemplate.class);
                            }
                        }),
                    () -> {
                        throw new RuntimeException("Script cache manager unavailable to handle LDAP filter");
                    });
        } else {
            filter.setFilter(filterQuery);
            if (values != null && !values.isEmpty()) {
                IntStream.range(0, values.size()).forEach(i -> {
                    val value = values.get(i);
                    if (filter.getFilter().contains("{" + i + '}')) {
                        filter.setParameter(i, value);
                    }
                    val name = paramName.get(i);
                    if (filter.getFilter().contains('{' + name + '}')) {
                        filter.setParameter(name, value);
                    }
                });
            }
        }

        LOGGER.debug("Constructed LDAP search filter [{}]", filter.format());

View on GitHub (pinned to e7288fc434)