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
- Change the expression so the last traversed member resolves to a class type (e.g. box the primitive or navigate a wrapper object).
- Make sure the referenced type is part of the application/indexed classes; if it lives in a dependency, ensure it is Jandex-indexed.
- Replace the nested-expression navigation with a custom Permission class or a PermissionChecker method that computes the value in plain code.
- 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
- Only navigate into class-typed members in params expressions
- Keep all traversed types Jandex-indexed (part of the app or indexed jars)
- Prefer custom Permission classes for non-trivial value derivation
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
- @PermissionChecker annotation placed on the '%s' attribute '
- @PermissionChecker annotation instance placed on the '%s' re
- Detected two @PermissionChecker annotations with same value
- @PermissionChecker method '%s' declares checked exceptions w
- Permission class '%s' has %d constructors, exactly one is al
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/88ec65c15a99fb3c.
Report an issue: GitHub.