quarkusio/quarkus · error · RuntimeException

Security annotations '<annotations>' cannot be applied on th

Error message

Security annotations '<annotations>' cannot be applied on the '<method>' method, please move the annotations to the class-level instead

What it means

When an endpoint class already has a class-level security annotation (e.g. @Basic), placing a method-level security annotation on one of its methods is rejected: the class-level mechanism governs and a per-method override of that category is not allowed. The build fails and points at the offending method, advising to consolidate annotations at class level.

Source

Thrown at extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpSecurityProcessor.java:892

                        for (MethodInfo method : interceptedClass.methods()) {
                            if (hasProperEndpointModifiers(method)) {
                                // avoid situation when resource method is annotated with @Basic, class is annotated
                                // with @Bearer, and we apply the @Bearer annotation
                                boolean interceptorBindingNotAppliedOnMethodLevel = !cache.containsKey(method)
                                        || !cache.get(method).contains(interceptorBinding);

                                if (interceptorBindingNotAppliedOnMethodLevel) {
                                    addInterceptedEndpoint(method, annotation, annotationBinding,
                                            bindingValueToInterceptedMethods, interceptorBinding);
                                }
                            }
                        }
                    } else {
                        MethodInfo mi = annotation.target().asMethod();

                        if (hasClassLevelSecurity.test(mi.declaringClass())) {
                            throw new RuntimeException(
                                    ("Security annotations '%s' cannot be applied on the '%s' method, "
                                            + "please move the annotations to the class-level instead").formatted(
                                                    Arrays.toString(Arrays.stream(interceptorBinding.getAnnotationBindings())
                                                            .toArray()),
                                                    toTargetName(mi)));
                        } else {
                            // only allow to combine interceptor bindings on endpoints if we explicitly support it
                            var appliedBindings = cache.computeIfAbsent(mi, a -> new ArrayList<>());
                            if (appliedBindings.contains(interceptorBinding)) {
                                if (!interceptorBinding.allowToRepeatThisInterceptorBinding()) {
                                    throw new RuntimeException(
                                            "Only one of the '%s' annotations can be applied on the '%s' method".formatted(
                                                    Arrays.toString(interceptorBinding.getAnnotationBindings()),
                                                    toTargetName(mi)));
                                }
                            } else {
                                appliedBindings.add(interceptorBinding);
                            }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove the method-level security annotation and rely on the class-level one
  2. Change the class-level annotation to the mechanism you actually need
  3. Remove the class-level annotation and annotate each method individually instead

Example fix

// before
@Basic
public class UserResource {
    @Form
    @GET
    public String get() { ... }
}
// after
@Basic
public class UserResource {
    @GET
    public String get() { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

if (Resource.class.isAnnotationPresent(Basic.class)
    && Arrays.stream(Resource.class.getDeclaredMethods())
        .anyMatch(m -> m.isAnnotationPresent(Form.class))) {
    throw new IllegalStateException("Method-level security annotation conflicts with class-level one");
}

Prevention

When it happens

Trigger: Annotating a method with an auth mechanism annotation (e.g. @Form) inside a class already annotated with a class-level security annotation (e.g. @Basic).

Common situations: Trying to 'override' the class mechanism for one endpoint; adding a new method with a copied annotation from another class; incremental security tightening that collided with existing class-level config.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/8ea126c74d108cf5. Report an issue: GitHub.