quarkusio/quarkus · error · IllegalStateException

Unable to derive the service interface for the generated Mut

Error message

Unable to derive the service interface for the generated Mutiny client: ${generatedClient}

What it means

During gRPC client generation, Quarkus scans the @GrpcClient-annotated injection point's type for the @MutinyClient annotation to determine which service interface the generated Mutiny client implements. If the generated client class carries no annotation other than @MutinyClient (so no service interface can be derived), the deployment fails. This usually means the class being injected is not a properly generated Mutiny gRPC client.

Source

Thrown at extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java:143

    void discoverInjectedClients(BeanDiscoveryFinishedBuildItem beanDiscovery,
            BuildProducer<GrpcClientBuildItem> clients,
            CombinedIndexBuildItem index) {

        Map<String, GrpcClientBuildItem> items = new HashMap<>();

        // Collect a map of service interface name to the generated client class
        Map<DotName, DotName> generatedClients = new HashMap<>();
        for (ClassInfo generatedClient : index.getIndex().getKnownDirectImplementors(GrpcDotNames.MUTINY_CLIENT)) {
            // Mutiny client implements MutinyClient and the service interface
            DotName serviceInterface = null;
            for (DotName name : generatedClient.interfaceNames()) {
                if (!name.equals(GrpcDotNames.MUTINY_CLIENT)) {
                    serviceInterface = name;
                    break;
                }
            }
            if (serviceInterface == null) {
                throw new IllegalStateException(
                        "Unable to derive the service interface for the generated Mutiny client: " + generatedClient);
            }
            generatedClients.put(serviceInterface, generatedClient.name());
        }

        for (InjectionPointInfo injectionPoint : beanDiscovery.getInjectionPoints()) {
            AnnotationInstance clientAnnotation = injectionPoint.getRequiredQualifier(GrpcDotNames.GRPC_CLIENT);
            if (clientAnnotation == null) {
                continue;
            }
            Set<String> registeredInterceptors = getRegisteredInterceptors(injectionPoint);

            String clientName;
            AnnotationValue clientNameValue = clientAnnotation.value();
            if (clientNameValue == null || clientNameValue.asString().equals(GrpcClient.ELEMENT_NAME)) {
                // Determine the service name from the annotated element
                if (clientAnnotation.target().kind() == Kind.FIELD) {
                    clientName = clientAnnotation.target().asField().name();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Inject the generated Mutiny service interface (e.g. Greeter from the .proto, or use @GrpcClient with the named client) instead of a custom class
  2. Verify the stubs are generated by Quarkus's protobuf codegen (mvn compile) and the class actually has both @MutinyClient and the service interface annotation
  3. Check that the @GrpcClient value or annotated type matches a service defined in your .proto files
  4. Clean and rebuild so generated sources are up to date

Example fix

// before
@Inject @GrpcClient MyCustomClient client;

// after
@Inject @GrpcClient("hello-service") Greeter greeter;
Defensive patterns

Strategy: validation

Validate before calling

// before injecting, check the type maps to a generated Mutiny client service interface
if (!(client instanceof io.quarkus.grpc.runtime.MutinyGrpc) && !isGeneratedMutinyClient(client.getClass())) {
    throw new IllegalArgumentException("Use the generated service interface, not " + client.getClass());
}

Type guard

static boolean isGeneratedMutinyClient(Class<?> c) {
    return c != null && java.util.Arrays.stream(c.getAnnotations())
        .anyMatch(a -> a.annotationType().getName().endsWith("MutinyClient"));
}

Prevention

When it happens

Trigger: A bean declares @Inject @GrpcClient SomeClient where SomeClient is annotated with @MutinyClient but no additional annotation naming the service interface; i.e. the type cannot be mapped back to a gRPC service interface during discoverInjectedClients.

Common situations: Hand-written classes annotated with @MutinyClient by mistake; injection of the wrong generated type after regenerating stubs; upgrading Quarkus or the gRPC code generator so the generated client no longer carries the expected service-interface annotation; copy-pasting a client class name that does not exist in the generated sources.

Related errors


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