flowable/flowable-engine · error · PropertyNotFoundException

error.property.method.notfound

Error message

error.property.method.notfound

What it means

After resolving the base object, AstMethod.eval asks the property node for the method name; if the property itself is null it throws PropertyNotFoundException('error.property.method.notfound' with name 'null'). This indicates the method-name part of the method expression evaluated to null rather than a String.

Solutions

  1. Ensure the variable/expression providing the method name is non-null and a non-empty String before evaluation.
  2. Default the name: ${obj[name != null ? name : 'defaultMethod']()} — or fix the map key/config value.
  3. Validate inputs feeding the dynamic method name (empty check) upstream.
  4. Switch to an explicit static method call if dynamic dispatch is not truly needed.

Example fix

// before
${bean[fnName]()}  // fnName is null
// after
${bean[fnName != null ? fnName : 'defaultFn']()}
Defensive patterns

Strategy: validation

Validate before calling

String methodName = (String) factory.createValueExpression(ctx, "${fnName}", String.class).getValue(context);
if (methodName == null || methodName.isEmpty()) {
    throw new IllegalStateException("Dynamic method name must be a non-empty String");
}

Type guard

boolean validDynamicMethodName(String s) { return s != null && !s.trim().isEmpty(); }

Try / catch

try {
    return expr.getValue(context);
} catch (PropertyNotFoundException e) {
    if (!e.getMessage().contains("method.notfound")) throw e;
    return fallbackMethod();
}

Prevention

When it happens

Trigger: Dynamic method access like ${obj[methodName]()} or bracket-style method selection where the inner expression returns null (unset variable, missing map key, resolver returning null).

Common situations: Dynamic dispatch from a configuration variable that was never set; map lookup for the method name returning null because the key is absent; expression built programmatically with a null method token.

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/0fe173e82d9f2be8. 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/AstMethod.java:93

	}

	@Override
	public void appendStructure(StringBuilder builder, Bindings bindings) {
		property.appendStructure(builder, bindings);
		params.appendStructure(builder, bindings);
	}

	protected Object eval(Bindings bindings, ELContext context, boolean answerNullIfBaseIsNull) {
		Object base = property.getPrefix().eval(bindings, context);
		if (base == null) {
			if (answerNullIfBaseIsNull) {
				return null;
			}
			throw new PropertyNotFoundException(LocalMessages.get("error.property.base.null", property.getPrefix()));
		}
		Object method = property.getProperty(bindings, context);
		if (method == null) {
			throw new PropertyNotFoundException(LocalMessages.get("error.property.method.notfound", "null", base));
		}
		String name = bindings.convert(method, String.class);

		context.setPropertyResolved(false);
		Object result = context.getELResolver().invoke(context, base, name, null, params.eval(bindings, context));
		if (!context.isPropertyResolved()) {
			throw new MethodNotFoundException(LocalMessages.get("error.property.method.notfound", name, base.getClass()));
		}
		return result;
	}

	@Override
	public Object eval(Bindings bindings, ELContext context) {
		return eval(bindings, context, true);
	}

    @Override
	public Object invoke(Bindings bindings, ELContext context, Class<?> returnType, Class<?>[] paramTypes, Object[] paramValues) {

View on GitHub (pinned to d6d39ce1c6)