{"record":{"id":"0bd4d60d69c612e0","repo":"quarkusio/quarkus","slug":"websocket-endpoint-s-superclass-s-is-secured","errorCode":null,"errorMessage":"WebSocket endpoint '%s' superclass '%s' is secured with the '%s' security annotation.\nOnly the HTTP upgrade can be secured with this annotation.\nPlease place the annotation on the endpoint class '%s' instead.\n","messagePattern":"WebSocket endpoint '(.+?)' superclass '(.+?)' is secured with the '(.+?)' security annotation\\.\nOnly the HTTP upgrade can be secured with this annotation\\.\nPlease place the annotation on the endpoint class '(.+?)' instead\\.\n","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java","lineNumber":993,"sourceCode":"        record PolicyToEndpoint(String policyName, String endpointId) {\n        }\n        return endpoints.stream()\n                .<PolicyToEndpoint> mapMulti((endpoint, consumer) -> {\n                    var beanName = endpoint.beanClassName();\n                    var beanClassInfo = index.getClassByName(beanName);\n                    if (securityTransformer.hasSecurityAnnotation(beanClassInfo, AUTHORIZATION_POLICY)) {\n                        var authorizationPolicyAnnotation = securityTransformer\n                                .findFirstSecurityAnnotation(beanClassInfo, AUTHORIZATION_POLICY).get();\n                        String policyName = authorizationPolicyAnnotation.value(\"name\").asString();\n                        consumer.accept(new PolicyToEndpoint(policyName, endpoint.id));\n                    } else {\n                        // we document that security annotations that secure the HTTP upgrade must be on the endpoint class\n                        var superName = beanClassInfo.superName();\n                        while (superName != null && !OBJECT.equals(superName)) {\n                            var superClass = index.getClassByName(superName);\n                            if (superClass != null\n                                    && securityTransformer.hasSecurityAnnotation(superClass, AUTHORIZATION_POLICY)) {\n                                throw new IllegalStateException(\"\"\"\n                                        WebSocket endpoint '%s' superclass '%s' is secured with the '%s' security annotation.\n                                        Only the HTTP upgrade can be secured with this annotation.\n                                        Please place the annotation on the endpoint class '%s' instead.\n                                        \"\"\".formatted(endpoint.id, superClass.name(), AuthorizationPolicy.class.getName(),\n                                        beanName));\n                            } else {\n                                superName = superClass == null ? null : superClass.superName();\n                            }\n                        }\n                    }\n                    beanClassInfo.methods().forEach(mi -> {\n                        if (securityTransformer.hasSecurityAnnotation(mi, AUTHORIZATION_POLICY)) {\n                            throw new IllegalStateException(\"\"\"\n                                    WebSocket endpoint '%s' has method '%s' secured with the '%s' security annotation.\n                                    Only the HTTP upgrade can be secured with this annotation.\n                                    Please place the annotation on the endpoint class instead.\n                                    \"\"\".formatted(beanName, mi.name(), AuthorizationPolicy.class.getName()));\n                        }","sourceCodeStart":975,"sourceCodeEnd":1011,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java#L975-L1011","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Move @AuthorizationPolicy from the superclass onto each concrete WebSocket endpoint class.","Remove the annotation from the shared base class and secure each endpoint individually.","If shared behavior is needed, keep the base class annotation-free and apply the policy per endpoint.","If you want one policy for many endpoints, consider securing the upgrade path via HTTP security policy configuration on the endpoint path instead."],"exampleFix":"// before\n@AuthorizationPolicy(name = \"admin\")\npublic abstract class BaseEndpoint { }\n\n@WebSocket(path = \"/ws\")\npublic class MyEndpoint extends BaseEndpoint { }\n\n// after\npublic abstract class BaseEndpoint { }\n\n@WebSocket(path = \"/ws\")\n@AuthorizationPolicy(name = \"admin\")\npublic class MyEndpoint extends BaseEndpoint { }","handlingStrategy":"validation","validationCode":"// Pre-check: AuthorizationPolicy must not sit on superclasses of a @WebSocket endpoint\nClass<?> c = MyEndpoint.class;\nwhile ((c = c.getSuperclass()) != null && c != Object.class) {\n    if (c.isAnnotationPresent(io.quarkus.security.AuthorizationPolicy.class))\n        throw new IllegalStateException(\"Move @AuthorizationPolicy from \" + c + \" to the endpoint class\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never place @AuthorizationPolicy on shared base classes of endpoints","Document in team conventions that security annotations go on the endpoint class","Review refactors that move security annotations into parent classes","Search codebase for @AuthorizationPolicy before adding WebSocket endpoints"],"tags":["quarkus","websockets-next","security","authorization","build-time"],"backgroundTag":"security-annotation-wrong-placement","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}