{"record":{"id":"e42b3e7a1edd303a","repo":"quarkusio/quarkus","slug":"the-original-implementation-class-of-a-grpc-servic","errorCode":null,"errorMessage":"The original implementation class of a gRPC service not found: ${originalImplName}","messagePattern":"The original implementation class of a gRPC service not found: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/devui/GrpcDevUIProcessor.java","lineNumber":245,"sourceCode":"        return null;\n    }\n\n    @BuildStep(onlyIf = IsLocalDevelopment.class)\n    JsonRPCProvidersBuildItem createJsonRPCServiceForCache() {\n        return new JsonRPCProvidersBuildItem(GrpcJsonRPCService.class);\n    }\n\n    private Collection<Class<?>> getGrpcServices(IndexView index) throws ClassNotFoundException {\n        ClassLoader tccl = Thread.currentThread().getContextClassLoader();\n        Set<String> serviceClassNames = new HashSet<>();\n        for (ClassInfo mutinyGrpc : index.getAllKnownImplementors(GrpcDotNames.MUTINY_GRPC)) {\n            // Find the original impl class\n            // e.g. examples.MutinyGreeterGrpc -> examples.GreeterGrpc\n            DotName originalImplName = DotName\n                    .createSimple(mutinyGrpc.name().toString().replace(MutinyGrpcGenerator.CLASS_PREFIX, \"\"));\n            ClassInfo originalImpl = index.getClassByName(originalImplName);\n            if (originalImpl == null) {\n                throw new IllegalStateException(\n                        \"The original implementation class of a gRPC service not found:\" + originalImplName);\n            }\n            // Must declare static io.grpc.ServiceDescriptor getServiceDescriptor()\n            MethodInfo getServiceDescriptor = originalImpl.method(\"getServiceDescriptor\");\n            if (getServiceDescriptor != null && Modifier.isStatic(getServiceDescriptor.flags())\n                    && getServiceDescriptor.returnType().name().toString().equals(ServiceDescriptor.class.getName())) {\n                serviceClassNames.add(getServiceDescriptor.declaringClass().name().toString());\n            }\n        }\n\n        serviceClassNames.add(HealthGrpc.class.getName());\n        DevConsoleManager.setGlobal(\"io.quarkus.grpc.serviceClassNames\", serviceClassNames);\n\n        List<Class<?>> serviceClasses = new ArrayList<>();\n        for (String className : serviceClassNames) {\n            serviceClasses.add(tccl.loadClass(className));\n        }\n        return serviceClasses;","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/devui/GrpcDevUIProcessor.java#L227-L263","documentation":"During Quarkus gRPC Dev UI processing, the build index is searched for the original (non-Mutiny) generated gRPC base class that corresponds to each Mutiny-generated service class. The Mutiny class name (e.g. examples.MutinyGreeterGrpc) is transformed by stripping the 'Mutiny' prefix, and the resulting class must exist in the Jandex index. If it does not, the deployment build fails with this IllegalStateException.","triggerScenarios":"A proto file produces Mutiny<Name>Grpc classes but the base <Name>Grpc class is missing from the index — e.g. quarkus-grpc code-gen is configured with generate-code non-mutiny disabled, the base generated class was excluded from indexing, or a custom protoc plugin setup generates only the Mutiny variant.","commonSituations":"Custom gRPC code generation configs that disable base class generation; mixing pre-generated stubs (only Mutiny classes committed) with Quarkus indexing; upgrading Quarkus and changing quarkus.generate-code.grpc options.","solutions":["Ensure the base (non-Mutiny) gRPC service classes are generated: keep the default quarkus.generate-code.grpc settings so both <Name>Grpc and Mutiny<Name>Grpc are produced.","If stubs are pre-generated and committed, make sure the base *Grpc classes are on the application classpath (not just the Mutiny ones) so Jandex can index them.","Check that generated sources are included in indexing (they normally are inside the same module); avoid exclude patterns in quarkus.index-dependency or jandex config that drop the generated package.","Rebuild cleanly (mvn clean install) so code generation re-runs and both classes are regenerated consistently."],"exampleFix":"// before (pom.xml disables base class generation)\n<plugin>org.xolstice.maven.plugins:protobuf-maven-plugin ... only mutiny generation</plugin>\n// after\nRemove custom exclusions and let quarkus-maven-plugin generate both:\n<Name>Grpc.java and Mutiny<Name>Grpc.java in the same package","handlingStrategy":"validation","validationCode":"// in a deployment test or startup check\nDotName impl = DotName.createSimple(mutinyName.replace(\"Mutiny\", \"\"));\nif (index.getClassByName(impl) == null) {\n    throw new IllegalStateException(\"Missing generated base class: \" + impl + \"; check gRPC code-gen config\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    processServices();\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"The original implementation class of a gRPC service not found\")) {\n        // fix code-gen config or add missing generated sources, then rebuild\n    } else throw e;\n}","preventionTips":["Keep default quarkus gRPC code-gen settings so both base and Mutiny classes are generated","Never commit only Mutiny*Grpc stubs without the base *Grpc classes","Avoid jandex/index exclude patterns covering generated packages","Run mvn clean after changing proto files or generator options"],"tags":["grpc","quarkus","build-time","codegen","jandex"],"backgroundTag":"generated-class-not-found","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"}