quarkusio/quarkus · error · IllegalArgumentException
Unsupported client type " + client.getClass()
Error message
Unsupported client type " + client.getClass()
What it means
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.
Source
Thrown at extensions/grpc/api/src/main/java/io/quarkus/grpc/GrpcClientUtils.java:39
* @return a client with headers attached
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> T attachHeaders(T client, Metadata extraHeaders) {
if (client == null) {
throw new NullPointerException("Cannot attach headers to a null client");
}
client = getProxiedObject(client);
if (client instanceof AbstractStub) {
return (T) ((AbstractStub) client).withInterceptors(MetadataUtils.newAttachHeadersInterceptor(extraHeaders));
} else if (client instanceof MutinyClient) {
MutinyClient mutinyClient = (MutinyClient) client;
AbstractStub stub = mutinyClient.getStub()
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(extraHeaders));
return (T) ((MutinyClient) client).newInstanceWithStub(stub);
} else {
throw new IllegalArgumentException("Unsupported client type " + client.getClass());
}
}
@SuppressWarnings("unchecked")
public static <T> T getProxiedObject(T client) {
// If we get a proxy, get the actual instance.
if (client instanceof ClientProxy) {
client = (T) ((ClientProxy) client).arc_contextualInstance();
}
return client;
}
}
View on GitHub (pinned to e1c734241f)
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
Example fix
// before
MyService mock = Mockito.mock(MyService.class); // not AbstractStub/MutinyClient
GrpcClientUtils.attachHeaders(mock, headers); // IllegalArgumentException
// after
AbstractStub stub = (AbstractStub) GrpcClientUtils.getProxiedObject(realClient);
MyService withHeaders = (MyService) stub.withInterceptors(
MetadataUtils.newAttachHeadersInterceptor(headers)); Defensive patterns
Strategy: type-guard
Validate before calling
Object unwrapped = GrpcClientUtils.getProxiedObject(client);
if (!(unwrapped instanceof io.grpc.stub.AbstractStub)
&& !(unwrapped instanceof io.quarkus.grpc.runtime.MutinyClient)) {
throw new IllegalArgumentException(
"attachHeaders requires a Quarkus gRPC client, got: " + unwrapped.getClass());
} Type guard
boolean isAttachableClient(Object c) {
Object u = GrpcClientUtils.getProxiedObject(c);
return u instanceof io.grpc.stub.AbstractStub
|| u instanceof io.quarkus.grpc.runtime.MutinyClient;
} Try / catch
try {
T withHeaders = GrpcClientUtils.attachHeaders(client, headers);
} catch (IllegalArgumentException e) {
log.warnf("Cannot attach headers: %s", e.getMessage()); // fall back to raw client
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Name cannot start with '/':${name}
- Predicate already set
- Location already set
- The unnamed module cannot be opened to other modules
- The unnamed module cannot be used as an opening module ident
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/e9b364e406238df0.
Report an issue: GitHub.