quarkusio/quarkus · error · java.lang.RuntimeException

Permission constructor '%s' first argument must be '%s'

Error message

Permission constructor '%s' first argument must be '%s'

What it means

The single constructor of a custom Permission class must accept the permission name as its first parameter of type java.lang.String, since Quarkus instantiates it with the @PermissionsAllowed value as the first argument. A constructor with no parameters or a non-String first parameter is rejected at build time.

Source

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

                                // to validate it
                                classSignatureToConstructor.put(key.classSignature(),
                                        key.permissionChecker.quarkusPermissionConstructor());
                                permissionCheckers.remove(key.permissionChecker);
                                continue;
                            }

                            // validate permission class
                            final ClassInfo clazz = index.getClassByName(key.clazz.name());
                            Objects.requireNonNull(clazz);
                            if (clazz.constructors().size() != 1) {
                                throw new RuntimeException(
                                        String.format("Permission class '%s' has %d constructors, exactly one is allowed",
                                                key.classSignature(), clazz.constructors().size()));
                            }
                            var constructor = clazz.constructors().get(0);
                            // first constructor parameter must be permission name
                            if (constructor.parametersCount() == 0 || !STRING.equals(constructor.parameterType(0).name())) {
                                throw new RuntimeException(
                                        String.format("Permission constructor '%s' first argument must be '%s'",
                                                clazz.name().toString(), String.class.getName()));
                            }
                            // rest of validation needs to be done for computed classes only and per each secured method
                            // therefore we do it later

                            // cache validation result
                            classSignatureToConstructor.put(key.classSignature(), constructor);
                        }
                    }
                }
            }
            if (!permissionCheckers.isEmpty()) {
                if (permissionCheckers.size() > 1) {
                    throw new RuntimeException("""
                            Found @PermissionChecker annotation instances that authorize the '%s' permissions, however
                            no @PermissionsAllowed annotation instance requires these permissions
                            """.formatted(String.join(",", permissionCheckers.values())));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a String permission-name parameter as the first constructor argument
  2. Reorder constructor parameters so String comes first
  3. If no name is meaningful, still accept it and ignore/store it in the constructor

Example fix

// before
public class MyPerm implements Permission {
    public MyPerm(Book b) {...}
}

// after
public class MyPerm implements Permission {
    public MyPerm(String name, Book b) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

Constructor<?> c = MyPerm.class.getConstructors()[0];
if (c.getParameterCount() == 0 || !c.getParameterTypes()[0].equals(String.class))
    throw new IllegalStateException("Permission constructor first parameter must be java.lang.String");

Prevention

When it happens

Trigger: Defining a permission class whose sole constructor is MyPerm(Book b) or MyPerm() and referencing it from @PermissionsAllowed; validated when validatePermissionClasses inspects constructor.parameterType(0).

Common situations: Modeling permissions around the checked resource only and omitting the name parameter; following an outdated tutorial predating the name-parameter requirement.

Related errors


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