flowable/flowable-engine · error · ELException
Expected LambdaExpression but got: " + (lambdaObj == null ?
Error message
Expected LambdaExpression but got: " + (lambdaObj == null ? "null" : lambdaObj.getClass().getName())
What it means
AstLambdaInvocation.eval evaluates the expression being invoked and requires it to be a LambdaExpression instance. If the evaluated target is null or any other type, it throws ELException describing the actual type. This means the code invoked something as a lambda function that did not evaluate to a lambda.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/ast/AstLambdaInvocation.java:46
public AstLambdaInvocation(AstNode lambdaNode, AstParameters params) {
this.lambdaNode = lambdaNode;
this.params = params;
}
@Override
public void appendStructure(StringBuilder builder, Bindings bindings) {
lambdaNode.appendStructure(builder, bindings);
params.appendStructure(builder, bindings);
}
@Override
public Object eval(Bindings bindings, ELContext context) {
// Evaluate the lambda expression
Object lambdaObj = lambdaNode.eval(bindings, context);
if (!(lambdaObj instanceof LambdaExpression)) {
throw new ELException("Expected LambdaExpression but got: " +
(lambdaObj == null ? "null" : lambdaObj.getClass().getName()));
}
LambdaExpression lambda = (LambdaExpression) lambdaObj;
// Evaluate the arguments
Object[] args = params.eval(bindings, context);
// Invoke the lambda
Object result = lambda.invoke(context, args);
return result;
}
@Override
public int getCardinality() {
return 2;
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Verify the invoked identifier is defined as a lambda, e.g. define it via the ELContext VariableMapper or a surrounding lambda expression.
- Null-check the variable before invocation: ${not empty f ? f(x) : ''}.
- Correct typos/scoping so the lambda variable is visible at the invocation site.
- Log/bind the value to confirm its runtime type before invoking it.
Example fix
// before
${myFuntion(42)} // typo, resolves to null
// after
${myFunction(42)} // where myFunction := x -> x + 1 Defensive patterns
Strategy: type-guard
Validate before calling
Object f = factory.createValueExpression(ctx, "${fn}", Object.class).getValue(context);
if (f == null) throw new IllegalStateException("Lambda variable 'fn' is not bound"); Type guard
boolean isLambda(Object v) { return v instanceof LambdaExpression; } Try / catch
try {
return lambdaInvocationExpr.getValue(context);
} catch (ELException e) {
if (!e.getMessage().startsWith("Expected LambdaExpression")) throw e;
return null; // or fallback invocation path
} Prevention
- Null-check function variables before invoking them in EL
- Define lambdas before/above their invocation scope
- Log the runtime type of dynamic call targets during development
When it happens
Trigger: Writing ${someIdentifier(args)} where someIdentifier evaluates to null or a non-lambda value (String, number, bean) instead of a lambda defined like (x -> x*2)(5); referencing a lambda variable before it is bound.
Common situations: Typos in lambda variable names; lambda defined in a different scope than the invocation; passing a non-lambda value into a position the caller treats as a function; null process variables used as functions.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Cannot coerce property to array index:
- error.compare.types
- error.negate
- error.coerce.type
- error.coerce.nonAbstract
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/597d1c5b76304551.
Report an issue: GitHub.