quarkusio/quarkus · error · java.lang.RuntimeException
@PermissionsAllowed annotation placed on the
Error message
@PermissionsAllowed annotation placed on the '%s' has inclusive relation between its permissions.
The '%s' permission has been matched with @PermissionChecker '%s', therefore you must also define
a @PermissionChecker for '%s' permissions.
What it means
When @PermissionsAllowed uses inclusive permission relations and one permission in the group is backed by a @PermissionChecker method, Quarkus requires every permission in that group to have a matching @PermissionChecker. If a permission (e.g. 'delete') matched a checker but a sibling permission in the same inclusive annotation has none, deployment fails with this message naming the annotation target, matched permission, existing checker, and the missing permission set.
Solutions
- Define a @PermissionChecker method for every permission listed in the inclusive @PermissionsAllowed annotation, e.g. add a method annotated @PermissionChecker("missing-permission") returning PermissionChecker in a CDI bean.
- Set inclusive=false on the annotation if an OR/one-of relation (each permission evaluated independently) is actually intended.
- Rename the permission in @PermissionsAllowed so it no longer accidentally matches a checker, if plain string permissions are wanted.
Example fix
// before
@PermissionsAllowed(value = {"read", "delete"}, inclusive = true) // 'read' has a checker, 'delete' does not
// after — add to a CDI bean:
@PermissionChecker("delete")
PermissionChecker deleteChecker() { return ctx -> ctx.getSubject().map(...).orElse(false); } Defensive patterns
Strategy: validation
Validate before calling
// Convention: maintain a single @PermissionChecker per permission name in one config class,
// and a test that every permission listed in inclusive @PermissionsAllowed annotations has a checker.
// grep your sources: every @PermissionsAllowed(value={...}, inclusive=true) name must have @PermissionChecker(name) Prevention
- For inclusive=true groups, define a @PermissionChecker for every listed permission before writing the annotation.
- Prefer inclusive=false (default OR semantics) unless all-permissions-required is truly needed.
- Centralize permission names as constants to avoid typos that break checker matching.
When it happens
Trigger: Using @PermissionsAllowed(value={...}, inclusive=true) where permission 'a' resolves to a @PermissionChecker method but sibling permission 'b' in the same annotation resolves to a plain StringPermission (no checker).
Common situations: Mixing @PermissionChecker-annotated producer methods with plain string permissions in one inclusive annotation; adding a new permission to an existing inclusive group without adding its checker; typos so a permission name no longer matches any checker method.
Related errors
- Found @PermissionChecker annotation instance declared on…
- @PermissionChecker declared on method
- @PermissionChecker ' ' matches permission ' ' and actions '…
- @PermissionsAllowed annotation placed on method
- @AuthorizationPolicy annotation placed on resource method
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/1335087759f96165.
Report an issue: GitHub.
Appendix: source
Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java:677
for (PermissionNameAndChecker checkerPermission : checkerPermissions) {
String permissionName = PermissionToActionUtil.parse(checkerPermission.permissionName).name();
for (var e : permissionToActions.entrySet()) {
PermissionNameAndChecker permissionNameKey = e.getKey();
// look for permission names that match our permission checker value (before action-to-perm separator)
// for example: read:it
if (permissionNameKey.checker == null && permissionNameKey.permissionName.equals(permissionName)) {
boolean hasActions = e.getValue() != null && !e.getValue().isEmpty();
final String permissionsJoinedWithActions;
if (hasActions) {
permissionsJoinedWithActions = e.getValue()
.stream()
.map(action -> permissionNameKey.permissionName + PERMISSION_TO_ACTION_SEPARATOR
+ action)
.collect(Collectors.joining(", "));
} else {
permissionsJoinedWithActions = permissionNameKey.permissionName;
}
throw new RuntimeException(
"""
@PermissionsAllowed annotation placed on the '%s' has inclusive relation between its permissions.
The '%s' permission has been matched with @PermissionChecker '%s', therefore you must also define
a @PermissionChecker for '%s' permissions.
"""
.formatted(toString(annotationTarget), permissionName,
toString(checkerPermission.checker.checkerMethod),
permissionsJoinedWithActions));
}
}
}
}
for (var permissionToAction : permissionToActions.entrySet().stream().sorted(PERMISSION_TO_ACTION_COMPARATOR)
.toList()) {
final var permissionNameKey = permissionToAction.getKey();
final var permissionActions = permissionToAction.getValue();
final var key = new PermissionKey(permissionNameKey.permissionName, permissionActions, params, classType,View on GitHub (pinned to e1c734241f)