quarkusio/quarkus · error · java.lang.RuntimeException
Class '%s' is annotated with '%s' and '%s' security annotati
Error message
Class '%s' is annotated with '%s' and '%s' security annotations,
however security annotations cannot be combined. What it means
A class annotated with a custom/additional security annotation (registered via AdditionalSecurityAnnotationBuildItem) cannot also carry a standard Quarkus security annotation such as @RolesAllowed/@Authenticated on the same target — security annotations cannot be combined. The build fails naming both annotations.
Source
Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityProcessor.java:1111
permitAllGatherer.gatherClassSecurityAnnotations();
authenticatedGatherer.gatherClassSecurityAnnotations();
denyAllGatherer.gatherClassSecurityAnnotations();
rolesAllowedGatherer.gatherClassSecurityAnnotations();
// we already validated that annotation target doesn't have more than one security check annotation
// now validate that the same annotation target doesn't have both security check and authorization policy annotation
securityTransformer.getSecurityAnnotationNames(AUTHORIZATION_POLICY)
.forEach(additionalSecAnnName -> index
.getAnnotations(additionalSecAnnName)
.stream()
.filter(ai -> ai.target().kind() == AnnotationTarget.Kind.CLASS)
.map(ai -> ai.target().asClass())
.filter(ai -> securityTransformer.hasSecurityAnnotation(ai, SECURITY_CHECK))
.findFirst()
.ifPresent(ci -> {
var securityAnnotation = securityTransformer.findFirstSecurityAnnotation(ci, SECURITY_CHECK)
.get().name();
throw new RuntimeException("""
Class '%s' is annotated with '%s' and '%s' security annotations,
however security annotations cannot be combined.
""".formatted(ci.name(), additionalSecAnnName, securityAnnotation));
}));
/*
* Handle additional secured methods by adding the denyAll/rolesAllowed check to all public non-static methods
* that don't have same security annotations
*/
for (AdditionalSecured additionalSecuredMethod : additionalSecuredMethods) {
if (!isPublicNonStaticNonConstructor(additionalSecuredMethod.methodInfo)) {
continue;
}
if (hasAdditionalSecurityAnnotations.test(additionalSecuredMethod.methodInfo)) {
continue;
}
AnnotationInstance alreadyExistingInstance = methodToInstanceCollector.get(additionalSecuredMethod.methodInfo);
if (additionalSecuredMethod.rolesAllowed.isPresent()) {View on GitHub (pinned to e1c734241f)
Solutions
- Remove one of the two annotations from the class — either the custom annotation or the standard security annotation.
- If the custom annotation should imply the standard check, model that in the annotation's own build step instead of combining annotations.
- Move the standard annotation to specific methods rather than combining them at class level, if the framework supports method-level separation.
Example fix
// before
@RolesAllowed("admin")
@CustomSecurity
public class AdminResource { ... }
// after
@CustomSecurity
public class AdminResource { ... } // handle roles inside the custom check Defensive patterns
Strategy: validation
Validate before calling
// fail fast if both a custom and a standard security annotation are present on a class
if (AdminResource.class.isAnnotationPresent(RolesAllowed.class) && AdminResource.class.isAnnotationPresent(CustomSecurity.class)) throw new IllegalStateException("security annotations cannot be combined"); Prevention
- Pick one security annotation scheme per class
- During custom-annotation migrations, sweep and remove legacy standard annotations
- Add an ArchUnit-style test enforcing the single-annotation rule
When it happens
Trigger: A class carries both a registered custom security annotation and a standard security annotation (e.g. @MyCustomAuth + @RolesAllowed) at the class level.
Common situations: Introducing a custom security annotation while legacy @RolesAllowed remains on the same class; library classes annotated with standard annotations being re-annotated with a company-specific annotation during a migration.
Related errors
- WebSocket endpoint '%s' requires secured HTTP upgrade but Qu
- Value not set for ${param}
- Non-static @Scheduled methods may not be declared on abstrac
- @PermissionChecker annotation placed on the '%s' attribute '
- @PermissionChecker annotation instance placed on the '%s' re
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/cbffe69272394a6f.
Report an issue: GitHub.