quarkusio/quarkus · error · java.lang.IllegalArgumentException
@PermissionChecker '%s' matches permission '%s' and actions
Error message
@PermissionChecker '%s' matches permission '%s' and actions '%s' on secured method '%s', but
the @PermissionsAllowed instance specified custom permission '%s'. Both cannot be supported.
Please choose one.
What it means
A @PermissionsAllowed entry can be satisfied either by a @PermissionChecker method or by a custom Permission implementation — not both. When a permission name (and actions) matches an existing @PermissionChecker but the annotation also specifies a non-default custom permission class, Quarkus throws this IllegalArgumentException in the PermissionKey constructor, naming the checker, the secured target, and the custom class.
Source
Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java:1210
}
private static final class PermissionKey {
private final String name;
private final Set<String> actions;
private final String[] params;
private final String[] paramsRemainder;
private final Type clazz;
private final boolean inclusive;
private final PermissionCheckerMetadata permissionChecker;
private PermissionKey(String name, Set<String> actions, String[] params, Type clazz, boolean inclusive,
PermissionCheckerMetadata permissionChecker, AnnotationTarget permsAllowedTarget) {
this.permissionChecker = permissionChecker;
this.name = name;
if (permissionChecker != null) {
if (isNotDefaultStringPermission(clazz)) {
throw new IllegalArgumentException("""
@PermissionChecker '%s' matches permission '%s' and actions '%s' on secured method '%s', but
the @PermissionsAllowed instance specified custom permission '%s'. Both cannot be supported.
Please choose one.
""".formatted(PermissionSecurityChecksBuilder.toString(permissionChecker.checkerMethod()), name,
actions, PermissionSecurityChecksBuilder.toString(permsAllowedTarget), clazz.name()));
}
this.clazz = Type.create(DotName.createSimple(permissionChecker.generatedClassName()), Type.Kind.CLASS);
} else {
this.clazz = clazz;
}
this.inclusive = inclusive;
if (!actions.isEmpty()) {
this.actions = actions;
} else {
this.actions = null;
}
if (params == null || params.length == 0) {View on GitHub (pinned to e1c734241f)
Solutions
- Choose one mechanism: remove the clazz attribute to use the @PermissionChecker, or remove/rename the @PermissionChecker method to keep the custom Permission class.
- Rename the custom permission so it no longer matches the checker's permission name if both permissions must coexist.
- Keep actions consistent — the collision is triggered by matched name+actions; adjusting actions alone does not fix it, resolve the overlap explicitly.
Example fix
// before (both defined)
@PermissionChecker("get")
PermissionChecker getChecker() { ... }
@PermissionsAllowed(value = "get", clazz = GetPermission.class)
// after (keep custom permission, drop checker)
@PermissionsAllowed(value = "get", clazz = GetPermission.class) Defensive patterns
Strategy: validation
Validate before calling
// Before adding a @PermissionChecker, check no @PermissionsAllowed with clazz= uses the same name: // grep -rn "clazz\s*=" src/main/java | while read l; do // name=$(extract value); grep -rn "@PermissionChecker(\"$name\")" src/main/java && echo "conflict: $l" // done
Prevention
- Decide per permission name: either a @PermissionChecker bean or a custom Permission class, never both.
- Keep a registry of permission names and their mechanism.
- When introducing a checker, search the codebase for custom permission classes with the same name.
When it happens
Trigger: @PermissionsAllowed(value="p", clazz=MyPermission.class) where a @PermissionChecker("p") method exists (with matching actions), so the name-based checker lookup collides with the explicit custom class.
Common situations: Adding a @PermissionChecker for a permission already secured with a custom Permission class; renaming a custom permission so it now collides with an existing checker name; team members independently wiring both mechanisms for the same permission.
Related errors
- @PermissionsAllowed annotation placed on the '%s' has inclus
- @PermissionsAllowed annotation placed on method '%s' has 'pa
- No '%s' formal parameter name matches '%s' Permission %s par
- @PermissionChecker declared on method '%s', but no matching
- Found @PermissionChecker annotation instance declared on the
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/a26c10c29a9a148d.
Report an issue: GitHub.