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

  1. Attach headers to the underlying stub directly instead of the decorator: cast/get the AbstractStub and call withInterceptors(MetadataUtils.newAttachHeadersInterceptor(headers))
  2. In tests, mock the MutinyClient or unwrap via GrpcClientUtils.getProxiedObject first and verify it is an AbstractStub
  3. 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

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


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