quarkusio/quarkus · error · java.lang.IllegalArgumentException

Method '%s#%s' parameter '%s' cannot be converted to a Permi

Error message

Method '%s#%s' parameter '%s' cannot be converted to a Permission constructor parameter
                            as required by the '@PermissionsAllowed#params' attribute. Parameter expression references '%s'
                            that has type '%s' which is not a class. Only class methods or fields can be mapped
                            to a Permission constructor parameter.

What it means

Quarkus Security's @PermissionsAllowed lets method parameters be converted into Permission constructor arguments via expression strings like 'param.attr.attr'. This error is thrown at build time when an intermediate expression segment resolves to a type that is not a class (e.g. a primitive, array, or interface-only resolution from the Jandex index), so nested navigation cannot continue. Only method or field accesses on classes can be mapped to Permission constructor parameters.

Source

Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java:1692

            validateNestedParams(nestedParams, 0, paramType, securedMethod, methodParamIdx);

            converterTasks.add(new ConverterTask(converterName, nestedParams, paramType));

            var methodHandleRuntimeVal = recorder.createPermissionMethodConverter(converterName, getClazz());
            converterNameToMethodHandle.put(converterName, methodHandleRuntimeVal);
            return converterName;
        }

        private void validateNestedParams(String[] nestedParams, int nestedParamIdx, Type outerType,
                MethodInfo securedMethod, int methodParamIdx) {
            if (nestedParamIdx == nestedParams.length) {
                return;
            }

            var paramExpression = nestedParams[nestedParamIdx];
            var outerClass = index.getClassByName(outerType.name());
            if (outerClass == null) {
                throw new IllegalArgumentException("""
                            Method '%s#%s' parameter '%s' cannot be converted to a Permission constructor parameter
                            as required by the '@PermissionsAllowed#params' attribute. Parameter expression references '%s'
                            that has type '%s' which is not a class. Only class methods or fields can be mapped
                            to a Permission constructor parameter.
                        """.formatted(securedMethod.declaringClass().name(), securedMethod.name(),
                        securedMethod.parameterName(methodParamIdx), paramExpression, outerType.name()));
            }

            var method = outerClass.method(paramExpression);
            if (method == null) {
                method = outerClass.method(toFieldGetter(paramExpression));
            }
            if (method != null) {
                if (!Modifier.isPublic(method.flags())) {
                    throw new IllegalArgumentException("""
                            Method '%s#%s' parameter '%s' cannot be mapped to a Permission constructor parameter,
                            because expression '%s' specified in the '@PermissionsAllowed#params' attribute is
                            accessible from method '%s#%s' which is not a public method.

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the expression so the last traversed member resolves to a class type (e.g. box the primitive or navigate a wrapper object).
  2. Make sure the referenced type is part of the application/indexed classes; if it lives in a dependency, ensure it is Jandex-indexed.
  3. Replace the nested-expression navigation with a custom Permission class or a PermissionChecker method that computes the value in plain code.
  4. If the member is a method or field on an interface, point the expression at the concrete class instead.

Example fix

// before
@PermissionsAllowed(value = "read", params = "order.qty")
public void read(Order order) { ... } // qty is int (not a class)

// after
@PermissionsAllowed(value = "read", params = "order.customer")
public void read(Order order) { ... } // navigate a class-typed member
Defensive patterns

Strategy: validation

Validate before calling

// before annotating, ensure every nested expression member resolves to a class type
// e.g. 'order.customer' - customer must be a class-typed field/getter, not int/arrays

Prevention

When it happens

Trigger: Annotating a method with @PermissionsAllowed(params="...") whose expression traverses into a member whose declared type is not resolvable as a class in the Jandex index (primitive types, arrays, or types not indexed).

Common situations: Navigating expressions into primitive getters (e.g. 'p.count' where count is int), into arrays, or into classes excluded from the index; using record components or Lombok-generated accessors whose resolved types confuse the expression walk.

Related errors


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