flowable/flowable-engine · error · MethodNotFoundException

Method not found: ${clazz}.${name}(${paramString(paramTypes)

Error message

Method not found: ${clazz}.${name}(${paramString(paramTypes)})

What it means

Flowable's EL method resolver throws MethodNotFoundException when no method on the target class matches the expression's method name and parameter types at all. It is the terminal 'nothing matched' case after findWrapper tried all candidates.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/javax/el/Util.java:261

            if (bestMatch.getExactCount() == paramCount - 1) {
                // Only one parameter is not an exact match - try using the
                // super class
                String errorMsg = "Unable to find unambiguous method: " + clazz + "." + name + "(" + paramString(paramTypes) + ")";
                match = findMostSpecificWrapper(ambiguousCandidates, paramTypes, bestMatch.getAssignableCount() > 0, errorMsg);
            } else {
                match = null;
            }

            if (match == null) {
                // If multiple methods have the same matching number of parameters
                // the match is ambiguous so throw an exception
                throw new MethodNotFoundException("Unable to find unambiguous method: " + clazz + "." + name + "(" + paramString(paramTypes) + ")");
            }
        }

        // Handle case where no match at all was found
        if (match == null) {
            throw new MethodNotFoundException("Method not found: " + clazz + "." + name + "(" + paramString(paramTypes) + ")");
        }

        return match;
    }

    /*
     * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
     */
    private static <T> Wrapper<T> findMostSpecificWrapper(Collection<Wrapper<T>> candidates, Class<?>[] matchingTypes, boolean elSpecific, String errorMsg) {
        List<Wrapper<T>> ambiguouses = new ArrayList<>();
        for (Wrapper<T> candidate : candidates) {
            boolean lessSpecific = false;

            Iterator<Wrapper<T>> it = ambiguouses.iterator();
            while (it.hasNext()) {
                int result = isMoreSpecific(candidate, it.next(), matchingTypes, elSpecific);
                if (result == 1) {
                    it.remove();

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Correct the method name or parameter usage in the EL expression
  2. Ensure the method exists with a signature compatible with the supplied arguments
  3. Re-version and redeploy process definitions after changing bean APIs so old expressions are not evaluated

Example fix

// before
${orderService.calculateTotl(order)}
// after
${orderService.calculateTotal(order)}
Defensive patterns

Strategy: validation

Validate before calling

boolean exists = Arrays.stream(clazz.getMethods()).anyMatch(m -> m.getName().equals(methodName));
if (!exists) throw new IllegalStateException("Method not on target class: " + clazz.getName() + "." + methodName);

Try / catch

try { return Util.result(context, base, method, argTypes, args); } catch (MethodNotFoundException e) { logger.error("Check EL expression against {}: {}", clazz, e.getMessage()); throw e; }

Prevention

When it happens

Trigger: Evaluating an EL method expression whose method name does not exist on the target class, or whose argument count/types match no overload; invoked from Util.result through Util.findWrapper.

Common situations: Typo in method name in a BPMN expression; method signature changed (renamed/params changed) while deployed process definitions still reference the old signature; invoking a method on the wrong bean type.

Related errors


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