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
- Ensure the calling component passes its configured ScriptCacheManager into newLdaptiveSearchFilter
- Check that the relevant CAS auto-configuration wires the script cache manager bean for your LDAP settings
- Rewrite the search filter as a static/template filter (non-Groovy) if scripting is not needed
- 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
- Pass a non-null ScriptCacheManager whenever scripted filters are possible
- Avoid Groovy-based LDAP filters unless scripting is genuinely required
- Ensure the scripting module is included in the CAS overlay
- Review upstream calls to LdapUtils for null cache-manager arguments
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
- No groovy script cache manager is available to execute…
- 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/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)