quarkusio/quarkus · error · IllegalArgumentException

Could not match a unique method name '<methodName>' for bean

Error message

Could not match a unique method name '<methodName>' for bean named <beanName> with class <class> Offending expression is <expression> of @PreAuthorize on method '<methodName>' of class <class>

What it means

Given @PreAuthorize like @bean.check(#id), the processor must find the bean method by name (plus boolean return type and parameter count). If more than one method in the bean class matches name, return type, and parameter count, the match is ambiguous and the build fails because the processor cannot know which overload to invoke.

Source

Thrown at extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/BeanMethodInvocationGenerator.java:274

        for (Type type : securedMethodInfo.parameterTypes()) {
            sb.append(classDescOf(type).descriptorString());
        }
        sb.append(")");
        return sb.toString();
    }

    private MethodInfo determineMatchingBeanMethod(String methodName, int methodParametersSize, ClassInfo beanClassInfo,
            MethodInfo securedMethodInfo, String expression, String beanName) {
        MethodInfo matchingBeanClassMethod = null;
        for (MethodInfo candidateMethod : beanClassInfo.methods()) {
            if (candidateMethod.name().equals(methodName) &&
                    Modifier.isPublic(candidateMethod.flags()) &&
                    DotNames.PRIMITIVE_BOOLEAN.equals(candidateMethod.returnType().name()) &&
                    candidateMethod.parametersCount() == methodParametersSize) {
                if (matchingBeanClassMethod == null) {
                    matchingBeanClassMethod = candidateMethod;
                } else {
                    throw new IllegalArgumentException(
                            "Could not match a unique method name '" + methodName + "' for bean named " + beanName
                                    + " with class " + beanClassInfo.name() + " Offending expression is " +
                                    expression + " of @PreAuthorize on method '" + methodName + "' of class "
                                    + securedMethodInfo.declaringClass());
                }
            }
        }
        if (matchingBeanClassMethod == null) {
            throw new IllegalArgumentException(
                    "Could not find a public, boolean returning method named '" + methodName + "' for bean named " + beanName
                            + " with class " + beanClassInfo.name() + " Offending expression is " +
                            expression + " of @PreAuthorize on method '" + methodName + "' of class "
                            + securedMethodInfo.declaringClass());
        }
        return matchingBeanClassMethod;
    }

}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Rename one of the overloaded bean methods and update the SpEL expression
  2. Change parameter counts or signatures so exactly one candidate matches
  3. Make one candidate non-public or change its boolean return type so it no longer matches
  4. Collapse the overloads into a single method handling both cases

Example fix

// before: bean has canRead(String,String) and canRead(String,Long); SpEL: @authz.canRead(#id,#tenant)
// after
public boolean canReadByIdAndTenant(String id, String tenant) // renamed; expression updated
Defensive patterns

Strategy: validation

Validate before calling

List<Method> candidates = Arrays.stream(beanClass.getMethods())
    .filter(m -> m.getName().equals(name) && m.getReturnType() == boolean.class
        && m.getParameterCount() == paramCount).collect(Collectors.toList());
if (candidates.size() != 1) {
    throw new IllegalStateException("@PreAuthorize bean method not unique: " + name);
}

Prevention

When it happens

Trigger: A bean referenced in @PreAuthorize has two public boolean methods with the same name and same number of parameters (differing only in parameter types), and the SpEL expression does not disambiguate them.

Common situations: Overloaded authorization methods like canAccess(String, String) and canAccess(String, Long); refactorings that added overloads; generic type erasure producing identical erased signatures.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/d3f18fe72c6a5724. Report an issue: GitHub.