flowable/flowable-engine · error · ELException

error.function.nomapper

error.function.nomapper

Error message

error.function.nomapper

What it means

Tree.bind() found function nodes in the parsed expression tree but the caller passed a null FunctionMapper. Functions cannot be resolved without a mapper, so JUEL throws ELException error.function.nomapper at bind time (i.e. when creating a TreeValueExpression/TreeMethodExpression).

Solutions

  1. Pass a FunctionMapper (e.g. Flowable's) that can resolve the functions used in the expression.
  2. Remove unsupported function calls from the expression if no mapper is intended.
  3. Check the expression with a parser/regex for 'prefix:name(' patterns before binding without a mapper.
  4. Catch ELException at bind time and fail fast with a clear configuration message.

Example fix

// before
new TreeValueExpression(treeStore, null, varMapper, converter, "${my:check(x)}", Boolean.class);
// after
new TreeValueExpression(treeStore, flowableFnMapper, varMapper, converter, "${my:check(x)}", Boolean.class);
Defensive patterns

Strategy: validation

Validate before calling

if (expression.contains(":") && expression.matches(".*\\$\\{[^}]*[a-zA-Z]+:[a-zA-Z]+\\(.*")) {
    Objects.requireNonNull(fnMapper, "Expression uses EL functions but no FunctionMapper was provided");
}

Try / catch

try {
    expr = new TreeValueExpression(store, fnMapper, varMapper, converter, expression, type);
} catch (ELException e) {
    throw new IllegalStateException("Expression '" + expression + "' needs a FunctionMapper", e);
}

Prevention

When it happens

Trigger: Building a TreeValueExpression/TreeMethodExpression (or calling tree.bind(...)) for an expression containing ${ns:fn(...)} function calls while passing fnMapper == null.

Common situations: Evaluating expressions that use custom EL functions in Flowable but constructing the expression without the Flowable function mapper; copying JUEL sample code that omits the FunctionMapper argument; refactoring that dropped the mapper parameter.

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/48bae7d4aee0ace8. 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:110

	 * @param varMapper the variable mapper to use
	 * @return tree bindings
	 */
	public Bindings bind(FunctionMapper fnMapper, VariableMapper varMapper) {
		return bind(fnMapper, varMapper, null);
	}

	/**
	 * Create a bindings.
	 * @param fnMapper the function mapper to use
	 * @param varMapper the variable mapper to use
	 * @param converter custom type converter
	 * @return tree bindings
	 */
	public Bindings bind(FunctionMapper fnMapper, VariableMapper varMapper, TypeConverter converter) {
		Method[] methods = null;
		if (!functions.isEmpty()) {
			if (fnMapper == null) {
				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));

View on GitHub (pinned to d6d39ce1c6)