quarkusio/quarkus · error · ProcessingException

Expected a ClientInvocationBuilder

Error message

Expected a ClientInvocationBuilder

What it means

UniInvokerProvider is a RxInvokerProvider for Uni in Quarkus' RESTEasy client integration. getRxInvoker only supports RESTEasy's ClientInvocationBuilder because it needs builder.rx() to obtain the CompletionStageRxInvoker underneath. If the SyncInvoker passed by the client runtime is not a ClientInvocationBuilder, it throws this ProcessingException, meaning the Uni reactive invoker is being requested from a non-RESTEasy client.

Source

Thrown at extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/java/io/quarkus/resteasy/mutiny/common/runtime/UniInvokerProvider.java:26

import jakarta.ws.rs.client.SyncInvoker;

import org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder;

public class UniInvokerProvider implements RxInvokerProvider<UniRxInvoker> {

    @Override
    public boolean isProviderFor(Class<?> clazz) {
        return UniRxInvoker.class.equals(clazz);
    }

    @Override
    public UniRxInvoker getRxInvoker(SyncInvoker syncInvoker, ExecutorService executorService) {
        if (syncInvoker instanceof ClientInvocationBuilder) {
            ClientInvocationBuilder builder = (ClientInvocationBuilder) syncInvoker;
            CompletionStageRxInvoker completionStageRxInvoker = builder.rx();
            return new UniRxInvokerImpl(completionStageRxInvoker);
        } else {
            throw new ProcessingException("Expected a ClientInvocationBuilder");
        }
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Use the RESTEasy Classic Quarkus client (rest-client / resteasy-client) so the invoker is a ClientInvocationBuilder.
  2. Remove conflicting JAX-RS client implementations from the classpath so the RESTEasy client is the resolved provider.
  3. Build invocations from a ResteasyClient WebTarget rather than wrapping the request, preserving the concrete ClientInvocationBuilder type.

Example fix

// before (wrong stack)
Client client = ClientBuilder.newClient(); // Jersey-like impl
client.target(url).request().rx(UniRxInvoker.class); // ProcessingException

// after (RESTEasy client)
ResteasyClient client = (ResteasyClient) ClientBuilder.newBuilder().build();
Uni<String> uni = client.target(url).request().rx(UniRxInvoker.class).get();
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(syncInvoker instanceof ClientInvocationBuilder)) {
    throw new IllegalStateException("UniRxInvoker requires the RESTEasy client; got " + syncInvoker.getClass());
}

Type guard

static boolean supportsUni(SyncInvoker invoker) {
    return invoker instanceof org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder;
}

Try / catch

try {
    UniRxInvoker invoker = webTarget.request().rx(UniRxInvoker.class);
} catch (ProcessingException e) {
    if (e.getMessage().contains("Expected a ClientInvocationBuilder")) {
        throw new IllegalStateException("Ensure the RESTEasy client provider is used (rest-client/quarkus resteasy-client)", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Requesting UniRxInvoker via syncInvoker.rx(UniRxInvoker.class) (or provider registration resolving to UniInvokerProvider) where the SyncInvoker supplied by the JAX-RS client is not org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.

Common situations: Mixing the Quarkus REST client with a different JAX-RS Client implementation on the classpath; using the mutiny Uni invoker extension without the RESTEasy client runtime; proxying or decorating the client request so the concrete builder type is lost.

Related errors


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