flowable/flowable-engine · error · ELException

error.identifier.method.invocation

Error message

error.identifier.method.invocation

What it means

Wraps java.lang.IllegalArgumentException raised during method.invoke(null, params) — the supplied arguments do not match the method's declared parameter types, or the method is not static/invoked with wrong receiver. The reflective invocation itself failed on argument binding. Note the message includes the exception, whereas the InvocationTargetException branch unwraps the cause.

Solutions

  1. Match argument types to the method signature (convert numerics/strings explicitly)
  2. Avoid nulls for primitive parameters (use wrapper parameter types or provide defaults)
  3. Ensure the resolved Method is static when invoked with a null receiver
  4. Log/print paramTypes vs the method's getParameterTypes() to spot mismatches

Example fix

// before: expression ${calc(orders)} where orders is String "5" and calc(int)
// after: set the variable as Integer
execution.setVariable("orders", Integer.parseInt(orderCountString));
Defensive patterns

Strategy: validation

Validate before calling

Object[] args = ...;
Class<?>[] declared = method.getParameterTypes();
if (args.length != declared.length) throw new IllegalArgumentException("Arg count mismatch for " + method);
for (int i = 0; i < declared.length; i++) {
  if (args[i] == null && declared[i].isPrimitive()) throw new IllegalArgumentException("Null for primitive param " + i);
}

Type guard

boolean argsCompatible(Object[] args, Class<?>[] types) {
  if (args.length != types.length) return false;
  for (int i = 0; i < types.length; i++) {
    if (args[i] == null ? types[i].isPrimitive() : !types[i].isInstance(args[i])) return false;
  }
  return true;
}

Try / catch

try {
  methodExpr.invoke(context, params);
} catch (ELException e) {
  if (e.getCause() instanceof IllegalArgumentException) {
    logger.error("Argument type mismatch invoking EL method: {}", e.getMessage());
  }
  throw e;
}

Prevention

When it happens

Trigger: Invoking a method expression with params whose runtime types (or count) do not match the Method's parameter types; passing null where a primitive is expected; invoking an instance method as static.

Common situations: EL expression passes a String where the delegate expects an Integer; flowable passes a DelegateExecution but the method expects a different type; primitive parameters receiving null argument values from variables.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/676e6df57b2c3d9b. 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/AstIdentifier.java:183

				public String getExpressionString() {
					return null;
				}
				@Override
				public int hashCode() {
					return 0;
				}
				@Override
				public boolean equals(Object obj) {
					return obj == this;
				}
				@Override
				public Object invoke(ELContext context, Object[] params) {
					try {
						return method.invoke(null, params);
					} catch (IllegalAccessException e) {
						throw new ELException(LocalMessages.get("error.identifier.method.access", name), e);
					} catch (IllegalArgumentException e) {
						throw new ELException(LocalMessages.get("error.identifier.method.invocation", name, e));
					} catch (InvocationTargetException e) {
						throw new ELException(LocalMessages.get("error.identifier.method.invocation", name, e.getCause()));
					}
				}			
				@Override
				public MethodInfo getMethodInfo(ELContext context) {
					return new MethodInfo(method.getName(), method.getReturnType(), method.getParameterTypes());
				}
			};
		} else if (value instanceof MethodExpression) {
			return (MethodExpression)value;
		}
		throw new MethodNotFoundException(LocalMessages.get("error.identifier.method.notamethod", name, value.getClass()));
	}

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

View on GitHub (pinned to d6d39ce1c6)