quarkusio/quarkus · error · java.lang.IllegalArgumentException
Detected two @PermissionChecker annotations with same value
Error message
Detected two @PermissionChecker annotations with same value '%s', annotated methods are:
- %s
- %s
What it means
Two methods were annotated with @PermissionChecker using the same 'value' permission name. Quarkus registers one generated Permission class per checker, keyed by permission name, so duplicates are ambiguous and rejected at build time.
Solutions
- Give each @PermissionChecker a unique 'value'
- Delete the redundant checker method if two methods implement the same check
- If both are needed for different resources, encode the distinction in the name, e.g. 'book:read' vs 'author:read'
Example fix
// before
@PermissionChecker("can-read") boolean canReadBook(Book b) {...}
@PermissionChecker("can-read") boolean canReadAuthor(Author a) {...}
// after
@PermissionChecker("book:read") boolean canReadBook(Book b) {...}
@PermissionChecker("author:read") boolean canReadAuthor(Author a) {...} Defensive patterns
Strategy: validation
Validate before calling
// collect values at startup-test time
Set<String> seen = new HashSet<>();
for (Method m : MyBeans.class.getDeclaredMethods()) {
PermissionChecker pc = m.getAnnotation(PermissionChecker.class);
if (pc != null && !seen.add(pc.value())) throw new IllegalStateException("Duplicate @PermissionChecker value: " + pc.value());
} Prevention
- Centralize permission names in an enum/constants class
- Use resource:action naming (book:read) to keep names unique
- Add a unit test scanning the classpath for duplicate permission values
When it happens
Trigger: Declaring @PermissionChecker("can-read") on two different methods (in the same or different beans); both are discovered by the Jandex index during the security deployment step.
Common situations: Duplicating a checker method in a subclass or copied bean without renaming the permission; renaming a method but not its permission value; merging branches that both added the same permission name.
Related errors
- Class is annotated with multiple security annotations and
- Class is annotated with multiple security annotations and
- Class ' ' is annotated with ' ' and ' ' security…
- Found DefaultSecurityCheckBuildItem items, please make sure…
- Found method annotated with the @AuthorizationPolicy…
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/8bcd25095d464a57.
Report an issue: GitHub.
Appendix: source
Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java:169
"@PermissionChecker annotation placed on the '%s' attribute 'value' must not be blank"
.formatted(toString(checkerMethod)));
}
boolean isBlocking = checkerMethod.hasDeclaredAnnotation(BLOCKING);
if (isBlocking && isReactive) {
throw new IllegalArgumentException("""
@PermissionChecker annotation instance placed on the '%s' returns 'Uni<Boolean>' and is
annotated with the @Blocking annotation; if you need to block, please return 'boolean'
""".formatted(toString(checkerMethod)));
}
var generatedPermissionClassName = getGeneratedPermissionName(checkerMethod, permissionCheckerIndex++);
var methodParamMappers = new MethodParameterMapper[checkerMethod.parametersCount()];
var generatedPermissionConstructor = getGeneratedPermissionConstructor(checkerMethod, methodParamMappers);
var checkerMetadata = new PermissionCheckerMetadata(checkerMethod, generatedPermissionClassName,
isReactive, generatedPermissionConstructor, methodParamMappers, isBlocking);
if (permissionCheckers.containsKey(permissionName)) {
throw new IllegalArgumentException("""
Detected two @PermissionChecker annotations with same value '%s', annotated methods are:
- %s
- %s
"""
.formatted(annotationInstance.value().asString(), toString(checkerMethod),
toString(permissionCheckers.get(permissionName).checkerMethod())));
}
permissionCheckers.put(permissionName, checkerMetadata);
}
return permissionCheckers;
}
private static boolean isUniBoolean(MethodInfo checkerMethod) {
if (checkerMethod.returnType().kind() == Type.Kind.PARAMETERIZED_TYPE) {
var parametrizedType = checkerMethod.returnType().asParameterizedType();
boolean returnsUni = UNI.equals(parametrizedType.name());
boolean booleanArg = parametrizedType.arguments().size() == 1View on GitHub (pinned to e1c734241f)