flowable/flowable-engine · error · FlowableException

Programmatic error: could not find method on class

Error message

Programmatic error: could not find method  on class 

What it means

AbstractFlowableVariableExpressionFunction resolves the static method backing a Flowable EL function (e.g. vars:get) by scanning the function class's public methods for one whose name matches the function's local name. If no matching public static method exists, the class was misconfigured/implemented incorrectly, so the engine throws this programmatic (internal) error instead of failing at expression evaluation time in a friendlier way.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/el/function/AbstractFlowableVariableExpressionFunction.java:67

    public AbstractFlowableVariableExpressionFunction(String functionName) {
        this(Collections.singletonList(functionName), functionName);
    }
    
    public AbstractFlowableVariableExpressionFunction(List<String> functionNameOptions, String functionName) {
        this.functionNamesOptions = new LinkedHashSet<>(functionNameOptions);
        this.functionName = functionName;

    }

    protected Method findMethod(String functionName) {
        Method[] methods = this.getClass().getMethods();
        for (Method method : methods) {
            if (Modifier.isStatic(method.getModifiers()) && method.getName().equals(functionName)) {
                return method;
            }
        }
        throw new FlowableException("Programmatic error: could not find method " + functionName + " on class " + this.getClass());
    }

    @Override
    public String prefix() {
        throw new UnsupportedOperationException("Function has more than one prefix");
    }

    @Override
    public Collection<String> prefixes() {
        return FUNCTION_PREFIXES;
    }

    @Override
    public String localName() {
        throw new UnsupportedOperationException("Function has more than one local name");
    }

    @Override

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure the subclass declares a public static method whose exact name equals the functionName passed to the constructor.
  2. Fix mismatched names: constructor arg, static method name, and localName() must agree.
  3. Make the implementing method public and static.
  4. Call functionMethod only during/after proper initialization — it is an internal invariant; hitting it means the function class itself is buggy.

Example fix

// before
public class MyVarFunction extends AbstractFlowableVariableExpressionFunction {
    public MyVarFunction() { super("get"); } // expects method 'get'
    public static String fetch(VariableContainer c, String name) { ... } // mismatch
}

// after
public class MyVarFunction extends AbstractFlowableVariableExpressionFunction {
    public MyVarFunction() { super("get"); }
    public static String get(VariableContainer c, String name) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

// at function class init time
boolean methodExists = java.util.Arrays.stream(getClass().getMethods())
    .anyMatch(m -> java.lang.reflect.Modifier.isStatic(m.getModifiers()) && m.getName().equals(functionName));
if (!methodExists) {
    throw new IllegalStateException("Function class " + getClass() + " lacks public static method " + functionName);
}

Try / catch

try {
    Method m = function.functionMethod();
} catch (FlowableException e) {
    throw new IllegalStateException("Misconfigured EL function class: " + function.getClass(), e);
}

Prevention

When it happens

Trigger: Creating a subclass of AbstractFlowableVariableExpressionFunction whose functionName/localName does not match any public static method declared on the subclass; renaming the implementing static method without updating the function's name constructor argument; calling functionMethod when the class declares the method as non-static or non-public.

Common situations: Writing a custom EL function class where the static method name and the name passed to the constructor diverge; copying an existing Flowable function and renaming the method but not the constructor argument; method made private/instance during refactoring.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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