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 String

What it means

When generating a security check from a Spring Security @PreAuthorize SpEL expression, a quoted literal argument (e.g. @bean.method('x')) must match the corresponding bean method parameter type. The processor found the parameter at index i is not String, so the generated invocation would be type-unsafe, and the build fails.

Source

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

                mc.body(bc -> {
                    LocalVar arcContainer = bc.localVar("arcContainer", bc
                            .invokeStatic(MethodDesc.of(Arc.class, "container", ArcContainer.class)));
                    LocalVar instanceHandle = bc.localVar("instanceHandle", bc.invokeInterface(
                            MethodDesc.of(ArcContainer.class, "instance", InstanceHandle.class, String.class),
                            arcContainer, Const.of(beanName)));
                    LocalVar bean = bc.localVar("bean", bc
                            .invokeInterface(MethodDesc.of(InstanceHandle.class, "get", Object.class), instanceHandle));
                    LocalVar castedBean = bc.localVar("castedBean", bc.cast(bean, classDescOf(beanClassInfo)));

                    List<Expr> argHandles = new ArrayList<>(finalBeanMethodArgumentExpressions.length);

                    for (int i = 0; i < finalBeanMethodArgumentExpressions.length; i++) {
                        String argumentExpression = finalBeanMethodArgumentExpressions[i];
                        String trimmedArgumentExpression = argumentExpression.trim();
                        if (argumentExpression.startsWith("'") && argumentExpression.endsWith("'")) { // hard coded string case
                            if (!DotNames.STRING.equals(matchingBeanMethod.parameterType(i).name())) {
                                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 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();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the bean method parameter type to String, or remove the quotes so the literal matches a non-String parameter
  2. Overload the bean method with a String-argument variant
  3. Rewrite the SpEL to reference the secured method's parameters (#id) instead of literals
  4. Convert the literal syntax to match the target parameter type

Example fix

// before: @PreAuthorize("@authz.hasRole('ADMIN')") with bean method
public boolean hasRole(int level)

// after
public boolean hasRole(String level) // or call hasRole(1) without quotes
Defensive patterns

Strategy: validation

Validate before calling

// check literal argument vs bean method signature
if (isQuotedLiteral(expr) && !beanMethod.getParameterTypes()[i].equals(String.class)) {
    throw new IllegalStateException("Literal '" + expr + "' does not match non-String param " + i);
}

Prevention

When it happens

Trigger: @PreAuthorize("@authz.check('literal')") where the target bean method's parameter at that position is not String (e.g. int, long, enum).

Common situations: SpEL expressions copied from Spring apps where the target method signature changed; wrong bean method matched due to overloads; hardcoded literal quoting mismatched with a non-String parameter.

Related errors


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