{"record":{"id":"fe6d65a06f56be62","repo":"quarkusio/quarkus","slug":"interceptor-class-interceptorclass-is-not-a-cdi","errorCode":null,"errorMessage":"Interceptor class ${interceptorClass} is not a CDI bean. Only CDI beans can be used as gRPC server/client interceptors. Add one of the scope-defining annotations (@Singleton, @ApplicationScoped, @RequestScoped) on the interceptor class.","messagePattern":"Interceptor class (.+?) is not a CDI bean\\. Only CDI beans can be used as gRPC server/client interceptors\\. Add one of the scope-defining annotations \\(@Singleton, @ApplicationScoped, @RequestScoped\\) on the interceptor class\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/Interceptors.java","lineNumber":35,"sourceCode":"    public static final int DUPLICATE_CONTEXT = Integer.MAX_VALUE - 5;\n    public static final int REQUEST_CONTEXT = Integer.MAX_VALUE - 50;\n    public static final int ROUTING_CONTEXT = Integer.MAX_VALUE - 55;\n    public static final int BLOCKING_HANDLER = Integer.MAX_VALUE - 60;\n    public static final int EXCEPTION_HANDLER = Integer.MAX_VALUE - 70;\n\n    static <T> List<T> getSortedPerServiceInterceptors(String name, Set<Class<?>> interceptorClasses) {\n        if (interceptorClasses.isEmpty()) {\n            return Collections.emptyList();\n        }\n        List<T> interceptors = new ArrayList<>();\n\n        for (Class<?> interceptorClass : interceptorClasses) {\n            // Note that additional qualifiers are ignored - @Any is required\n            InstanceHandle<?> interceptorInstance = Arc.container().instance(interceptorClass, Any.Literal.INSTANCE);\n            @SuppressWarnings(\"unchecked\")\n            T interceptor = (T) interceptorInstance.get();\n            if (interceptor == null) {\n                throw new IllegalArgumentException(\"Interceptor class \" + interceptorClass + \" is not a CDI bean. \" +\n                        \"Only CDI beans can be used as gRPC server/client interceptors. Add one of the scope-defining annotations\"\n                        +\n                        \" (@Singleton, @ApplicationScoped, @RequestScoped) on the interceptor class.\");\n            }\n            interceptors.add(interceptor);\n        }\n        interceptors.sort(Interceptors.INTERCEPTOR_COMPARATOR);\n        return interceptors;\n    }\n\n    static <T> List<T> getSortedPerServiceInterceptors(Set<Class<?>> interceptorClasses) {\n        if (interceptorClasses.isEmpty()) {\n            return Collections.emptyList();\n        }\n        List<T> interceptors = new ArrayList<>();\n\n        for (Class<?> interceptorClass : interceptorClasses) {\n            // Note that additional qualifiers are ignored - @Any is required","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/Interceptors.java#L17-L53","documentation":"Quarkus gRPC resolves per-service server/client interceptor classes from the CDI container at runtime. This error is thrown when Arc.container().instance(interceptorClass, Any.Literal.INSTANCE) returns an instance that is null, meaning the class is not a managed CDI bean. Only beans with a scope-defining annotation can be instantiated and injected by CDI, so plain classes registered as interceptors are rejected with this IllegalArgumentException.","triggerScenarios":"Registering a class in quarkus.grpc.clients.<name>.interceptor or quarkus.grpc.server.interceptors config (or via @GrpcService/Interceptors registration) where the class has no CDI scope annotation, so the Arc container lookup by the interceptor class returns null in getSortedPerServiceInterceptors.","commonSituations":"Developer writes a plain `implements ServerInterceptor` class without @Singleton/@ApplicationScoped, copies a gRPC interceptor from a non-Quarkus project, or the class is a CDI bean but in a package excluded from bean discovery (no beans.xml needed nowadays but must be in an indexed archive), or the class has a non-default-constructor pattern Arc cannot resolve.","solutions":["Annotate the interceptor class with a scope-defining annotation such as @Singleton (preferred for stateless interceptors).","If the interceptor needs dependencies, use @ApplicationScoped and @Inject fields.","Verify the class is part of the Quarkus application archive (in src/main/java of the app or an indexed library JAR with a Jandex index).","Confirm the fully-qualified class name in the configuration property matches the annotated class exactly (no typos)."],"exampleFix":"// before\npublic class TracingInterceptor implements ServerInterceptor { ... }\n\n// after\nimport jakarta.inject.Singleton;\n\n@Singleton\npublic class TracingInterceptor implements ServerInterceptor { ... }","handlingStrategy":"validation","validationCode":"// before configuring the interceptor\nClass<?> clazz = TracingInterceptor.class;\nif (!clazz.isAnnotationPresent(jakarta.inject.Singleton.class)\n    && !clazz.isAnnotationPresent(jakarta.enterprise.context.ApplicationScoped.class)\n    && !clazz.isAnnotationPresent(jakarta.enterprise.context.RequestScoped.class)) {\n    throw new IllegalStateException(clazz + \" must be a scope-annotated CDI bean\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ManagedChannel c = grpcClient.getChannel();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"not a CDI bean\")) {\n        log.error(\"Add @Singleton/@ApplicationScoped to the interceptor class: \" + e.getMessage());\n    } else { throw e; }\n}","preventionTips":["Always annotate gRPC interceptors with @Singleton by default.","Keep interceptors in the application archive so ArC indexes them.","Add an integration test that starts the app and resolves every configured interceptor at boot."],"tags":["grpc","cdi","interceptor","quarkus"],"backgroundTag":"bean-not-cdi-managed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}