flowable/flowable-engine · error · ELException
error.coerce.nonAbstract
error.coerce.nonAbstract
Error message
error.coerce.nonAbstract
What it means
When coercing a lambda to a functional-interface type, JUEL builds a dynamic Proxy that forwards every call to the lambda. The proxy's handler assumes each invoked Method is the interface's single abstract method; if a non-abstract method (e.g. a default method or toString) is dispatched through the handler and is not abstract, it throws this ELException.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/misc/TypeConverterImpl.java:363
try {
editor.setAsText(value);
} catch (IllegalArgumentException e) {
throw new ELException(LocalMessages.get("error.coerce.value", value, value.getClass(), type), e);
}
}
return editor.getValue();
}
}
protected <T> T coerceToFunctionalInterface(LambdaExpression lambdaExpression, Class<T> type) {
Supplier<T> proxy = () -> {
// Create a dynamic proxy for the functional interface
@SuppressWarnings("unchecked")
T result = (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type },
(Object obj, Method method, Object[] args) -> {
// Functional interfaces have a single, abstract method
if (!Modifier.isAbstract(method.getModifiers())) {
throw new ELException(LocalMessages.get("error.coerce.nonAbstract", type, method));
}
return lambdaExpression.invoke(args);
});
return result;
};
return proxy.get();
}
protected Object coerceToPrimitive(Object value, Class<?> type) {
if (type == long.class) {
return coerceToLong(value);
}
if (type == double.class) {
return coerceToDouble(value);
}
if (type == boolean.class) {
return coerceToBoolean(value);
}View on GitHub (pinned to d6d39ce1c6)
Solutions
- Invoke only the single abstract method of the target interface through the proxy; refactor callers that rely on default methods.
- Change the target type to a plain functional interface without default methods.
- Upgrade JUEL/Odysseus EL to a version whose proxy handler handles non-abstract (default/Object) methods properly.
- Catch ELException around the lambda invocation and handle the unsupported method dispatch.
Example fix
// before MyFn f = (MyFn) lambda; f.defaultHelper(); // default method -> ELException // after MyFn f = (MyFn) lambda; f.apply(x); // call only the SAM
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure the target is a true SAM interface without default methods used at runtime
for (Method m : targetType.getMethods()) {
if (!Modifier.isAbstract(m.getModifiers()) && m.getDeclaringClass() != Object.class && !m.isDefault()) {
// suspicious target for lambda coercion
}
} Type guard
boolean isSamInterface(Class<?> t) {
if (t == null || !t.isInterface()) return false;
Method[] abs = t.getMethods();
return Arrays.stream(t.getMethods())
.filter(m -> Modifier.isAbstract(m.getModifiers()))
.count() == 1;
} Try / catch
try {
result = samProxy.invoke(args);
} catch (ELException e) {
log.warn("Non-abstract method dispatched on lambda proxy", e);
result = handleDefaultMethod(args);
} Prevention
- Only coerce lambdas to plain SAM interfaces without default methods.
- Do not call default or Object methods through EL lambda proxies.
- Pin/upgrade the EL library version known to handle default methods.
- Add tests invoking every method your code calls on coerced lambdas.
When it happens
Trigger: A lambda expression is coerced (coerceToFunctionalInterface) to a target functional interface, and at invocation time the proxy dispatches a Method that fails Modifier.isAbstract, e.g. a default method on the interface being called.
Common situations: Coercing lambdas to interfaces that include default methods (Java 8+ interfaces like Comparator with reversed()); calling Object methods or default methods through the proxy; custom functional interfaces with defensive default methods.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Lambda parameters marker should not be evaluated
- Expected LambdaExpression but got: " + (lambdaObj == null ?
- Only '${argCount}' arguments were provided for a lambda expr
- <exception message from evaluation failure>
- Variable id cannot be empty
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/63e3f17cd96aeb63.
Report an issue: GitHub.