flowable/flowable-engine · error · ELException
Class ${className} not found
Error message
Class ${className} not found What it means
load() looks up a class name from the factory properties (keyed by the requesting class's name) and loads it via the context class loader or Class.forName. A ClassNotFoundException is wrapped as ELException 'Class X not found' — the property names a class that does not exist on the classpath.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/ExpressionFactoryImpl.java:427
protected TreeBuilder createDefaultTreeBuilder(Feature... features) {
return new Builder(features);
}
private Class<?> load(Class<?> clazz, Properties properties) {
if (properties != null) {
String className = properties.getProperty(clazz.getName());
if (className != null) {
ClassLoader loader;
try {
loader = Thread.currentThread().getContextClassLoader();
} catch (Exception e) {
throw new ELException("Could not get context class loader", e);
}
try {
return loader == null ? Class.forName(className) : loader.loadClass(className);
} catch (ClassNotFoundException e) {
throw new ELException("Class " + className + " not found", e);
} catch (Exception e) {
throw new ELException("Class " + className + " could not be instantiated", e);
}
}
}
return null;
}
@Override
public final <T> T coerceToType(Object obj, Class<T> targetType) {
return converter.convert(obj, targetType);
}
@Override
public final ObjectValueExpression createValueExpression(Object instance, Class<?> expectedType) {
return new ObjectValueExpression(converter, instance, expectedType);
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Correct the fully-qualified class name in the properties to a class present on the classpath
- Add the jar/module containing the named class to the runtime classpath
- Remove the property entry to fall back to the built-in default implementation
Example fix
// before de.odysseus.el.TypeConverter = com.acme.OldConverter // after de.odysseus.el.TypeConverter = com.acme.NewConverter
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check every class name referenced by factory properties
String name = props.getProperty("de.odysseus.el.TypeConverter");
if (name != null && Class.forName(name, false, getClass().getClassLoader()) == null) {
throw new IllegalStateException("Configured class not on classpath: " + name);
} Try / catch
try {
ExpressionFactory factory = new ExpressionFactoryImpl(props);
} catch (ELException e) {
if (e.getCause() instanceof ClassNotFoundException) {
log.error("Add missing jar or correct the FQN in EL properties: {}", e.getCause().getMessage(), e);
}
throw e;
} Prevention
- Grep properties files for FQNs and verify each against the classpath in CI
- Update property files whenever referenced classes are renamed or repackaged
- Use a dependency report to confirm the jar containing custom classes ships in the artifact
When it happens
Trigger: ExpressionFactoryImpl construction where a properties key (e.g. the TypeConverter or TreeBuilder property key) maps to a class name that is misspelled, not deployed, or in a jar missing from the runtime classpath.
Common situations: Renamed/moved class after a library upgrade while properties file still references the old FQN; missing dependency jar in the deployed WAR; typo in fully-qualified class name in juel/EL properties.
Related errors
- TypeConverter ${clazz} could not be instantiated
- Builder ${clazz} is missing constructor (can't pass features
- TreeBuilder ${clazz} could not be instantiated
- Unabled to find ExpressionFactory of type ${className}
- Cannot read default EL properties
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/78e721f7d5c25656.
Report an issue: GitHub.