flowable/flowable-engine · error · MethodNotFoundException

Unable to find unambiguous method

Error message

Unable to find unambiguous method: ${clazz}.${name}(${paramString(paramTypes)})

What it means

Flowable's EL method resolver throws MethodNotFoundException when more than one method on the target class matches the expression's parameter count/types equally, so no unambiguous best match exists. Rather than guessing, the resolver fails fast. This mirrors the ambiguity handling in Tomcat's org.apache.el.util.ReflectionUtil.

Solutions

  1. Rename one of the ambiguous overloaded methods or use distinct method names in expressions
  2. Cast or coerce the argument explicitly in the expression so exactly one overload matches
  3. Pass arguments whose runtime types unambiguously select a single overload

Example fix

// before: bean has handle(String) and handle(Integer), expression arg type ambiguous
${taskService.handle(value)}
// after: dedicated method avoids ambiguity
${taskService.handleString(value)}
Defensive patterns

Strategy: validation

Validate before calling

long matches = Arrays.stream(clazz.getMethods()).filter(m -> m.getName().equals(name) && isApplicable(m, argValues)).count();
if (matches > 1) throw new IllegalStateException("Ambiguous EL method: " + name);

Try / catch

try { method = Util.findMethod(context, clazz, base, name, argTypes, args); } catch (MethodNotFoundException e) { if (e.getMessage().startsWith("Unable to find unambiguous")) { log.warn("Ambiguous overload for {}", name); } throw e; }

Prevention

When it happens

Trigger: Evaluating an EL method expression where the target class has overloaded methods with equal match quality for the supplied argument types, e.g. two overloads both applicable after coercion, reached via Util.findWrapper from Util.result.

Common situations: Overloaded service methods (e.g. foo(String) and foo(Integer)) invoked with an EL expression whose argument type is ambiguous (null literal, or a value EL coerces either way); adding an overload to a bean that is also referenced from existing process expressions.

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/70a690131a177af3. Report an issue: GitHub.

Appendix: source

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

            } else if (cmp == 0) {
                ambiguousCandidates.add(entry.getKey());
                multiple = true;
            }
        }
        if (multiple) {
            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;

View on GitHub (pinned to d6d39ce1c6)