flowable/flowable-engine · error · ELException
error.function.invocation
Error message
error.function.invocation
What it means
AstFunction.eval() invokes the EL function reflectively; when the invoked method itself throws an exception, it surfaces as InvocationTargetException, and AstFunction rethrows it as ELException with message 'error.function.invocation: <functionName>' and the original cause attached. The EL layer is not failing — your function's code threw.
Solutions
- Read e.getCause() on the ELException to see the function's original exception and stack trace.
- Add defensive checks inside the EL function for null/invalid inputs.
- Catch and wrap errors inside the function to produce a domain-specific message.
- Test the function directly with the argument values present in the failing expression.
Example fix
// before
public static int len(String s) { return s.length(); } // NPE on null
// after
public static int len(String s) { return s == null ? 0 : s.length(); } Defensive patterns
Strategy: try-catch
Validate before calling
// smoke-test each registered function with representative args Object result = method.invoke(null, sampleArgs); // must not throw
Try / catch
try {
return expr.getValue(context);
} catch (ELException e) {
Throwable cause = e.getCause();
log.error("EL function failed: {}", cause, cause);
throw new IllegalStateException("Function invocation failed: " + cause.getMessage(), cause);
} Prevention
- Always inspect the ELException cause chain — the real bug is in your function code.
- Make EL functions null-safe and input-validating.
- Wrap function bodies to convert technical failures into domain errors.
- Unit-test functions with the argument shapes used in expressions.
When it happens
Trigger: Evaluating an expression that calls a registered EL function whose implementation throws any runtime/checked exception, e.g. ${myfn:parse(date)} where parse() throws a ParseException or NPE on null input.
Common situations: Null or malformed arguments passed to EL functions in process conditions/listeners; function code hitting environmental failures (IO, DB) during expression evaluation; API changes in the function class after a dependency upgrade.
Related errors
- Builder is missing constructor (can't pass features)
- Cannot find method with parameters in
- Class could not be instantiated
- Class not found
- Could not get context class loader
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b4990a4953105a45.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/ast/AstFunction.java:123
Object param = getParam(i).eval(bindings, context);
if (param != null || types[i].isPrimitive()) {
params[i] = bindings.convert(param, types[i]);
}
}
}
}
return method.invoke(base, params);
}
@Override
public Object eval(Bindings bindings, ELContext context) {
Method method = bindings.getFunction(index);
try {
return invoke(bindings, context, null, method);
} catch (IllegalAccessException e) {
throw new ELException(LocalMessages.get("error.function.access", name), e);
} catch (InvocationTargetException e) {
throw new ELException(LocalMessages.get("error.function.invocation", name), e.getCause());
}
}
@Override
public String toString() {
return name;
}
@Override
public void appendStructure(StringBuilder b, Bindings bindings) {
b.append(bindings != null && bindings.isFunctionBound(index) ? "<fn>" : name);
params.appendStructure(b, bindings);
}
@Override
public int getIndex() {
return index;
}View on GitHub (pinned to d6d39ce1c6)