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");
}
@OverrideView on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure the subclass declares a public static method whose exact name equals the functionName passed to the constructor.
- Fix mismatched names: constructor arg, static method name, and localName() must agree.
- Make the implementing method public and static.
- 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
- Keep the constructor's functionName, the public static method name, and localName(s) in sync.
- Declare function methods public static, returning types compatible with EL.
- Add a unit test that calls functionMethod()/localNames() for every custom function class.
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
- TypeConverter ${clazz} could not be instantiated
- Builder ${clazz} is missing constructor (can't pass features
- TreeBuilder ${clazz} could not be instantiated
- Class ${className} not found
- error.function.access
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/823f968bda765572.
Report an issue: GitHub.