quarkusio/quarkus · error · IllegalArgumentException

Parameter with index <i> of method '<beanMethod>' found in e

Error message

Parameter with index <i> of method '<beanMethod>' found in expression '<expression>' in the @PreAuthorize annotation on method <method> of class <class> is not of type <expectedType>

What it means

When translating @PreAuthorize SpEL that passes a secured-method parameter into a bean method (e.g. @bean.check(#id)), the processor checks that the bean method's parameter type at index i equals the referenced secured-method parameter type. A mismatch means the generated bytecode invocation would not type-check, so the build fails.

Source

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

                                        + "' in the @PreAuthorize annotation on method " + securedMethodInfo.name()
                                        + " of class "
                                        + securedMethodInfo.declaringClass() + " is not of type String");
                            }

                            argHandles.add(Const.of(argumentExpression.replace("'", "")));
                        } else if (trimmedArgumentExpression.matches(METHOD_PARAMETER_REGEX)) { // secured method's parameter case
                            checkRequiresMethodArguments[0] = true;
                            Matcher parameterMatcher = METHOD_PARAMETER_PATTERN.matcher(trimmedArgumentExpression);
                            if (!parameterMatcher.find()) { // should never happen
                                throw createGenericMalformedException(securedMethodInfo, expression);
                            }

                            // this is the index of the parameter we care about
                            int parameterIndex = getParameterIndex(securedMethodInfo, parameterMatcher.group(1), expression);

                            DotName expectedType = securedMethodInfo.parameterType(parameterIndex).name();
                            if (!matchingBeanMethod.parameterType(i).name().equals(expectedType)) {
                                throw new IllegalArgumentException("Parameter with index " + i + " of method '" + beanMethodName
                                        + "' found in expression '" + trimmedArgumentExpression
                                        + "' in the @PreAuthorize annotation on method " + securedMethodInfo.name()
                                        + " of class "
                                        + securedMethodInfo.declaringClass() + " is not of type " + expectedType);
                            }

                            /*
                             * the check method from AbstractBeanMethodSecurityCheck contains all parameters in an object array
                             * so we need to use that to read the value at runtime
                             */
                            argHandles.add(bc.localVar("methodArg" + parameterIndex,
                                    bc.get(methodArgsParam.elem(parameterIndex))));
                        } else if (trimmedArgumentExpression
                                .matches("(authentication.)?principal.username")) { // username use case
                            LocalVar principal = bc.localVar("principal", bc.invokeInterface(
                                    MethodDesc.of(SecurityIdentity.class, "getPrincipal", Principal.class),
                                    securityIdentityParam));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Align the bean method parameter type with the secured method parameter type (or vice versa)
  2. Rename the bean method or adjust the SpEL to target the correct overload
  3. Accept a wider type (e.g. Object) in the bean and convert inside
  4. Reference the secured-method parameter by its exact name so getParameterIndex resolves correctly

Example fix

// before
@PreAuthorize("@authz.canRead(#id)") public void get(String id) // bean: canRead(long id)

// after: bean method changed to
public boolean canRead(String id)
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> expected = securedMethod.getParameterTypes()[refIndex];
Class<?> actual = beanMethod.getParameterTypes()[i];
if (!actual.equals(expected)) {
    throw new IllegalStateException("SpEL arg type mismatch: " + actual + " vs " + expected);
}

Prevention

When it happens

Trigger: @PreAuthorize("@authz.canRead(#userId)") where authz.canRead expects a type different from userId's type in the secured method (e.g. String vs Long), or an overloaded bean method matched the wrong variant.

Common situations: Refactoring one method without updating the SpEL; autoboxing mismatches (long vs Long); wrong overload picked among methods with the same name and parameter count.

Related errors


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