flowable/flowable-engine · error · ELException

error.method.invalid

Error message

error.method.invalid

What it means

AstRightValue nodes cannot invoke methods; invoke() is final and unconditionally throws ELException. Method invocation is only valid on AST nodes that resolve to an object or method binding (e.g. AstMethod, AstIdentifier resolving to a bean). This is the EL engine's way of saying the expression does not denote a callable.

Solutions

  1. Make the expression a proper method call: add parentheses and arguments, e.g. '${myBean.doWork()}' or '${myBean.doWork(param)}'.
  2. Confirm the expression evaluates to an object with an invocable method; check the root node type before calling invoke.
  3. If you only need the value, call getValue on the ValueExpression instead of invoke on a MethodExpression.

Example fix

// before
String expr = "${myBean.doWork}"; // invoked -> ELException error.method.invalid
// after
String expr = "${myBean.doWork()}";
Defensive patterns

Strategy: validation

Validate before calling

if (!exprString.matches(".*\\)\\s*$")) { throw new IllegalArgumentException("Expression is not a method call: " + exprString); }

Type guard

boolean isMethodExpression(String expr) { return expr.contains("(") && expr.trim().endsWith(")"); }

Try / catch

try { methodExpression.invoke(ctx, params); } catch (ELException e) { log.error("Not invokable: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling invoke()/MethodExpression.invoke (or getMethodInfo path) on an expression whose parsed AST root is an rvalue, e.g. invoking MethodExpression created from a literal or operator expression like '${1 + 1}' or '${a.b}' used where a method expression was expected.

Common situations: Passing a value expression string where a method expression is required (missing parentheses/arguments, e.g. '${myBean.doWork}' instead of '${myBean.doWork()}'); wiring Flowable expression attributes with non-callable expressions.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/232b252514143020. 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/AstRightValue.java:68

		return true;
	}

	/**
	 * non-lvalues are always readonly, so throw an exception
	 */
	@Override
	public final void setValue(Bindings bindings, ELContext context, Object value) {
		throw new ELException(LocalMessages.get("error.value.set.rvalue", getStructuralId(bindings)));
	}

	@Override
	public final MethodInfo getMethodInfo(Bindings bindings, ELContext context, Class<?> returnType, Class<?>[] paramTypes) {
		return null;
	}

	@Override
	public final Object invoke(Bindings bindings, ELContext context, Class<?> returnType, Class<?>[] paramTypes, Object[] paramValues) {
		throw new ELException(LocalMessages.get("error.method.invalid", getStructuralId(bindings)));
	}

	@Override
	public final boolean isLeftValue() {
		return false;
	}
	
	@Override
	public boolean isMethodInvocation() {
		return false;
	}
	
	@Override
	public final ValueReference getValueReference(Bindings bindings, ELContext context) {
		return null;
	}
}

View on GitHub (pinned to d6d39ce1c6)