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

  1. Read e.getCause() on the ELException to see the function's original exception and stack trace.
  2. Add defensive checks inside the EL function for null/invalid inputs.
  3. Catch and wrap errors inside the function to produce a domain-specific message.
  4. 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

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


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)