flowable/flowable-engine · error · MethodNotFoundException

error.identifier.method.notfound

Error message

error.identifier.method.notfound

What it means

Thrown from getMethodExpression when evaluating the identifier yields null. A method expression ${myBean.myMethod(...)} requires the identifier to reference an object (or java.lang.reflect.Method), but the resolved value was null, so there is no method to invoke. Reported as MethodNotFoundException naming the identifier.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/ast/AstIdentifier.java:145

	@Override
	public boolean isReadOnly(Bindings bindings, ELContext context) {
		ValueExpression expression = bindings.getVariable(index);
		if (expression != null) {
			return expression.isReadOnly(context);
		}
		context.setPropertyResolved(false);
		boolean result = context.getELResolver().isReadOnly(context, null, name);
		if (!context.isPropertyResolved()) {
			throw new PropertyNotFoundException(LocalMessages.get("error.identifier.property.notfound", name));
		}
		return result;
	}

	protected MethodExpression getMethodExpression(Bindings bindings, ELContext context, Class<?> returnType, Class<?>[] paramTypes) {
		Object value = eval(bindings, context);
		if (value == null) {
			throw new MethodNotFoundException(LocalMessages.get("error.identifier.method.notfound", name));
		}
		if (value instanceof Method) {
			final Method method = findAccessibleMethod((Method)value);
			if (method == null) {
				throw new MethodNotFoundException(LocalMessages.get("error.identifier.method.notfound", name));
			}
			if (!ignoreReturnType && returnType != null && !returnType.isAssignableFrom(method.getReturnType())) {
				throw new MethodNotFoundException(LocalMessages.get("error.identifier.method.returntype", method.getReturnType(), name, returnType));
			}
			if (!Arrays.equals(method.getParameterTypes(), paramTypes)) {
				throw new MethodNotFoundException(LocalMessages.get("error.identifier.method.notfound", name));
			}
			return new MethodExpression() {
				private static final long serialVersionUID = 1L;
				@Override
				public boolean isLiteralText() {
					return false;
				}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure the referenced bean/variable is non-null when the expression evaluates (check Spring bean registration, @Component scan)
  2. Set the process variable before the listener/condition runs
  3. Fix the identifier spelling
  4. Add a resolver (e.g. Spring bean resolver) so the name maps to the actual bean

Example fix

// before: variable 'delegateBean' never set, expression ${delegateBean.execute(execution)}
// after: provide the bean
execution.setVariable("delegateBean", applicationContext.getBean(MyDelegate.class));
Defensive patterns

Strategy: type-guard

Validate before calling

Object bean = applicationContext.getBeanProvider(DelegateType.class).getIfAvailable();
if (bean == null) throw new IllegalStateException("delegateBean not registered in Spring context");

Type guard

boolean methodTargetPresent(String varName, VariableScope scope) {
  return scope.getVariable(varName) != null;
}

Try / catch

try {
  methodExpr.invoke(context, params);
} catch (MethodNotFoundException e) {
  logger.error("Method target '{}' is null; check bean/variable wiring", e.getMessage());
  throw new FlowableException("Missing method expression target", e);
}

Prevention

When it happens

Trigger: Calling MethodExpression.invoke() or getMethodInfo() (via AstIdentifier.invoke/getMethodInfo) where the identifier evaluates to null — e.g. variable not set or bean property is null.

Common situations: Task listener/execution listener delegation expression pointing at a bean that is null; Spring bean not yet injected or missing from application context; process variable holding the delegate cleared before the listener fires.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/406775741a56b94c. Report an issue: GitHub.