quarkusio/quarkus · error · java.lang.RuntimeException
Permission class '%s' has %d constructors, exactly one is al
Error message
Permission class '%s' has %d constructors, exactly one is allowed
What it means
When a custom Permission class referenced by @PermissionsAllowed is validated, Quarkus requires exactly one constructor because it must programmatically instantiate the permission (passing the permission name plus secured method parameters). A class with zero or multiple constructors cannot be wired unambiguously and fails the build.
Source
Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java:394
for (List<PermissionKey> keyList : keyLists) {
for (PermissionKey key : keyList) {
if (!classSignatureToConstructor.containsKey(key.classSignature())) {
if (key.permissionChecker != null) {
// QuarkusPermission we generated for the @PermissionChecker
// won't be in the index and as we generated it, we don't need
// 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);
}
}
}View on GitHub (pinned to e1c734241f)
Solutions
- Keep exactly one constructor on the permission class
- Make the single constructor take the permission name (String) as first parameter
- Remove extra overloaded constructors or delete Lombok annotations generating multiple constructors
Example fix
// before
public class MyPerm implements Permission {
public MyPerm() {...}
public MyPerm(String name, Book b) {...}
}
// after
public class MyPerm implements Permission {
public MyPerm(String name, Book b) {...}
} Defensive patterns
Strategy: validation
Validate before calling
Constructor<?>[] ctors = MyPerm.class.getConstructors();
if (ctors.length != 1) throw new IllegalStateException("Permission class must declare exactly one constructor, found " + ctors.length); Prevention
- Give permission classes a single explicit constructor
- Avoid Lombok annotations that generate extra constructors on permission classes
- Document the one-constructor contract in the team's security guidelines
When it happens
Trigger: A custom permission class used in @PermissionsAllowed (e.g. @PermissionsAllowed(value="read", action=MyPerm.class)) declares more than one constructor (plus the implicit default counts too) and is found by validatePermissionClasses during build.
Common situations: Adding a convenience overloaded constructor to an existing permission class; forgetting that the no-arg default constructor counts when another is added; Lombok @AllArgsConstructor plus default constructor.
Related errors
- Permission constructor '%s' first argument must be '%s'
- @CachedResults class must be an interface or declare a no-ar
- @PermissionChecker annotation placed on the '%s' attribute '
- @PermissionChecker annotation instance placed on the '%s' re
- Detected two @PermissionChecker annotations with same value
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/45c486bfac32a95f.
Report an issue: GitHub.