quarkusio/quarkus · error · IllegalStateException

WebSocket endpoint '%s' superclass '%s' is secured with the

Error message

WebSocket endpoint '%s' superclass '%s' is secured with the '%s' security annotation.
Only the HTTP upgrade can be secured with this annotation.
Please place the annotation on the endpoint class '%s' instead.

What it means

AuthorizationPolicy secures the HTTP upgrade request only, so the websockets-next processor requires it to be placed on the WebSocket endpoint class itself. If the annotation is found on a superclass of the endpoint, the build fails with guidance to move the annotation. This is a deliberate placement rule, not a bug.

Source

Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:993

        record PolicyToEndpoint(String policyName, String endpointId) {
        }
        return endpoints.stream()
                .<PolicyToEndpoint> mapMulti((endpoint, consumer) -> {
                    var beanName = endpoint.beanClassName();
                    var beanClassInfo = index.getClassByName(beanName);
                    if (securityTransformer.hasSecurityAnnotation(beanClassInfo, AUTHORIZATION_POLICY)) {
                        var authorizationPolicyAnnotation = securityTransformer
                                .findFirstSecurityAnnotation(beanClassInfo, AUTHORIZATION_POLICY).get();
                        String policyName = authorizationPolicyAnnotation.value("name").asString();
                        consumer.accept(new PolicyToEndpoint(policyName, endpoint.id));
                    } else {
                        // we document that security annotations that secure the HTTP upgrade must be on the endpoint class
                        var superName = beanClassInfo.superName();
                        while (superName != null && !OBJECT.equals(superName)) {
                            var superClass = index.getClassByName(superName);
                            if (superClass != null
                                    && securityTransformer.hasSecurityAnnotation(superClass, AUTHORIZATION_POLICY)) {
                                throw new IllegalStateException("""
                                        WebSocket endpoint '%s' superclass '%s' is secured with the '%s' security annotation.
                                        Only the HTTP upgrade can be secured with this annotation.
                                        Please place the annotation on the endpoint class '%s' instead.
                                        """.formatted(endpoint.id, superClass.name(), AuthorizationPolicy.class.getName(),
                                        beanName));
                            } else {
                                superName = superClass == null ? null : superClass.superName();
                            }
                        }
                    }
                    beanClassInfo.methods().forEach(mi -> {
                        if (securityTransformer.hasSecurityAnnotation(mi, AUTHORIZATION_POLICY)) {
                            throw new IllegalStateException("""
                                    WebSocket endpoint '%s' has method '%s' secured with the '%s' security annotation.
                                    Only the HTTP upgrade can be secured with this annotation.
                                    Please place the annotation on the endpoint class instead.
                                    """.formatted(beanName, mi.name(), AuthorizationPolicy.class.getName()));
                        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Move @AuthorizationPolicy from the superclass onto each concrete WebSocket endpoint class.
  2. Remove the annotation from the shared base class and secure each endpoint individually.
  3. If shared behavior is needed, keep the base class annotation-free and apply the policy per endpoint.
  4. If you want one policy for many endpoints, consider securing the upgrade path via HTTP security policy configuration on the endpoint path instead.

Example fix

// before
@AuthorizationPolicy(name = "admin")
public abstract class BaseEndpoint { }

@WebSocket(path = "/ws")
public class MyEndpoint extends BaseEndpoint { }

// after
public abstract class BaseEndpoint { }

@WebSocket(path = "/ws")
@AuthorizationPolicy(name = "admin")
public class MyEndpoint extends BaseEndpoint { }
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check: AuthorizationPolicy must not sit on superclasses of a @WebSocket endpoint
Class<?> c = MyEndpoint.class;
while ((c = c.getSuperclass()) != null && c != Object.class) {
    if (c.isAnnotationPresent(io.quarkus.security.AuthorizationPolicy.class))
        throw new IllegalStateException("Move @AuthorizationPolicy from " + c + " to the endpoint class");
}

Prevention

When it happens

Trigger: A @WebSocket endpoint class extends a base class annotated with @AuthorizationPolicy; during build the processor walks superName up to Object and throws on the first superclass carrying the annotation.

Common situations: Extracting a shared secured base class for multiple endpoints and assuming annotation inheritance works; refactoring security from endpoint classes into an abstract parent; copying HTTP-endpoint patterns (where class inheritance of security annotations is expected) into WebSocket endpoints.

Related errors


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