flowable/flowable-engine · error · ELException
error.function.params
error.function.params
Error message
error.function.params
What it means
Tree.bind() resolved the function Method but its arity does not match the parsed call: for varargs functions the method may take at most paramCount+1 parameters, otherwise it must take exactly paramCount. JUEL throws ELException error.function.params naming the function image.
Solutions
- Update the expression to pass the number of arguments the registered Method expects.
- Change the registered Method (or add an overload) to match the arity used in expressions; prefer a varargs signature for flexible arity.
- Re-scan deployed process definitions for function calls after changing function signatures.
- Catch ELException and validate function arity in a startup test suite.
Example fix
// before
// method: sum(int a, int b); expression: ${math:sum(1, 2, 3)} -> error.function.params
// after
public static int sum(int... values) { ... } // or fix the expression to ${math:sum(1, 2)} Defensive patterns
Strategy: validation
Validate before calling
Method m = fnMapper.resolveFunction(prefix, localName);
if (m != null && argCount != m.getParameterCount()
&& !(m.isVarArgs() && m.getParameterCount() <= argCount + 1)) {
throw new IllegalStateException(fn + " expects " + m.getParameterCount() + " args, got " + argCount);
} Try / catch
try {
bindings = tree.bind(fnMapper, varMapper, converter);
} catch (ELException e) {
throw new ConfigurationException("Function signature mismatch: " + e.getMessage(), e);
} Prevention
- Keep function signatures stable; deprecate before changing parameter counts.
- Prefer varargs methods for functions with optional arguments.
- Run a deploy-time pass that binds all expressions to catch arity errors early.
- Version function namespaces when signatures change.
When it happens
Trigger: Expression calls ns:fn(a, b) but the resolved Method (a) has no varargs and a different number of parameters than the call, or (b) is varargs with more declared parameters than call args + 1.
Common situations: A registered function's signature was changed (parameters added/removed) while expressions in process definitions still use the old arity; overloading confusion where resolveFunction picked a wrong overload; copy-pasted expressions reused with a different function of the same name.
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
- Builder is missing constructor (can't pass features)
- Cannot change fixed value with
- Cannot coerce property to array index:
- Cannot coerce property to array index:
- Cannot find method with parameters in
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/41a7c4f887b0769e.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/Tree.java:128
throw new ELException(LocalMessages.get("error.function.nomapper"));
}
methods = new Method[functions.size()];
for (int i = 0; i < functions.size(); i++) {
FunctionNode node = functions.get(i);
String image = node.getName();
Method method = null;
int colon = image.indexOf(':');
if (colon < 0) {
method = fnMapper.resolveFunction("", image);
} else {
method = fnMapper.resolveFunction(image.substring(0, colon), image.substring(colon + 1));
}
if (method == null) {
throw new ELException(LocalMessages.get("error.function.notfound", image));
}
if (node.isVarArgs() && method.isVarArgs()) {
if (method.getParameterTypes().length > node.getParamCount() + 1) {
throw new ELException(LocalMessages.get("error.function.params", image));
}
} else {
if (method.getParameterTypes().length != node.getParamCount()) {
throw new ELException(LocalMessages.get("error.function.params", image));
}
}
methods[node.getIndex()] = method;
}
}
ValueExpression[] expressions = null;
if (identifiers.size() > 0) {
expressions = new ValueExpression[identifiers.size()];
for (int i = 0; i < identifiers.size(); i++) {
IdentifierNode node = identifiers.get(i);
ValueExpression expression = null;
if (varMapper != null) {
expression = varMapper.resolveVariable(node.getName());
}View on GitHub (pinned to d6d39ce1c6)