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.
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)
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
- @PermissionChecker annotation placed on the '%s' attribute '
- @PermissionChecker annotation instance placed on the '%s' re
- @PermissionChecker method '%s' declares checked exceptions w
- Permission class '%s' has %d constructors, exactly one is al
- Permission constructor '%s' first argument must be '%s'
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/8bcd25095d464a57.
Report an issue: GitHub.