{"record":{"id":"e9b364e406238df0","repo":"quarkusio/quarkus","slug":"unsupported-client-type-client-getclass","errorCode":null,"errorMessage":"Unsupported client type \" + client.getClass()","messagePattern":"Unsupported client type \" \\+ client\\.getClass\\(\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/grpc/api/src/main/java/io/quarkus/grpc/GrpcClientUtils.java","lineNumber":39,"sourceCode":"     * @return a client with headers attached\n     */\n    @SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n    public static <T> T attachHeaders(T client, Metadata extraHeaders) {\n        if (client == null) {\n            throw new NullPointerException(\"Cannot attach headers to a null client\");\n        }\n\n        client = getProxiedObject(client);\n\n        if (client instanceof AbstractStub) {\n            return (T) ((AbstractStub) client).withInterceptors(MetadataUtils.newAttachHeadersInterceptor(extraHeaders));\n        } else if (client instanceof MutinyClient) {\n            MutinyClient mutinyClient = (MutinyClient) client;\n            AbstractStub stub = mutinyClient.getStub()\n                    .withInterceptors(MetadataUtils.newAttachHeadersInterceptor(extraHeaders));\n            return (T) ((MutinyClient) client).newInstanceWithStub(stub);\n        } else {\n            throw new IllegalArgumentException(\"Unsupported client type \" + client.getClass());\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getProxiedObject(T client) {\n        // If we get a proxy, get the actual instance.\n        if (client instanceof ClientProxy) {\n            client = (T) ((ClientProxy) client).arc_contextualInstance();\n        }\n        return client;\n    }\n}\n","sourceCodeStart":21,"sourceCodeEnd":52,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/grpc/api/src/main/java/io/quarkus/grpc/GrpcClientUtils.java#L21-L52","documentation":"attachHeaders() only knows how to wrap clients that are either a gRPC AbstractStub or a Quarkus MutinyClient. If the unwrapped client is neither, it throws IllegalArgumentException listing the actual class. This guards against passing unproxyable or foreign client implementations.","triggerScenarios":"Passing a client object that is not generated by the Quarkus gRPC client machinery — e.g. a mock created with Mockito (which is neither AbstractStub nor MutinyClient), a manually constructed stub wrapper, or a custom client implementation class.","commonSituations":"Unit tests mocking the gRPC client then calling GrpcClientUtils.attachHeaders on the mock; wrapping clients in custom decorators/delegates that hide the underlying stub; version drift where a client implementation no longer extends the supported types.","solutions":["Attach headers to the underlying stub directly instead of the decorator: cast/get the AbstractStub and call withInterceptors(MetadataUtils.newAttachHeadersInterceptor(headers))","In tests, mock the MutinyClient or unwrap via GrpcClientUtils.getProxiedObject first and verify it is an AbstractStub","Ensure you pass the Quarkus-generated client bean, not a hand-rolled wrapper"],"exampleFix":"// before\nMyService mock = Mockito.mock(MyService.class); // not AbstractStub/MutinyClient\nGrpcClientUtils.attachHeaders(mock, headers); // IllegalArgumentException\n// after\nAbstractStub stub = (AbstractStub) GrpcClientUtils.getProxiedObject(realClient);\nMyService withHeaders = (MyService) stub.withInterceptors(\n    MetadataUtils.newAttachHeadersInterceptor(headers));","handlingStrategy":"type-guard","validationCode":"Object unwrapped = GrpcClientUtils.getProxiedObject(client);\nif (!(unwrapped instanceof io.grpc.stub.AbstractStub)\n    && !(unwrapped instanceof io.quarkus.grpc.runtime.MutinyClient)) {\n    throw new IllegalArgumentException(\n        \"attachHeaders requires a Quarkus gRPC client, got: \" + unwrapped.getClass());\n}","typeGuard":"boolean isAttachableClient(Object c) {\n    Object u = GrpcClientUtils.getProxiedObject(c);\n    return u instanceof io.grpc.stub.AbstractStub\n        || u instanceof io.quarkus.grpc.runtime.MutinyClient;\n}","tryCatchPattern":"try {\n    T withHeaders = GrpcClientUtils.attachHeaders(client, headers);\n} catch (IllegalArgumentException e) {\n    log.warnf(\"Cannot attach headers: %s\", e.getMessage()); // fall back to raw client\n}","preventionTips":["Never pass Mockito mocks or hand-rolled decorators into GrpcClientUtils","If wrapping clients, keep the underlying AbstractStub accessible and attach interceptors at the stub level","Check the generated client type in target/generated-sources when unsure what attachHeaders supports"],"tags":["grpc","illegal-argument","unsupported-type"],"backgroundTag":"unsupported-client-type","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}