quarkusio/quarkus · error · IllegalStateException

A REST Client RestResponse object was returned from a server

Error message

A REST Client RestResponse object was returned from a server endpoint. This is not supported because it carries connection-specific headers that are not suitable for forwarding. Please create a new RestResponse by extracting the status, entity and headers you need.

What it means

Same family as the client-Response case but for org.jboss.resteasy.reactive.client.RestResponse: a server endpoint returned the RestResponse instance obtained from a REST Client call (RestResponseImpl flagged as client response). Its connection-specific headers make it unsuitable for direct forwarding, so IllegalStateException is thrown.

Source

Thrown at independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java:104

            if (existing.getMediaType() != null) {
                requestContext.setResponseContentType(existing.getMediaType());
                mediaTypeAlreadyExists = true;
            }
            EncodedMediaType produces = requestContext.getResponseContentType();
            if (!mediaTypeAlreadyExists && (produces != null) && (responseBuilder.getEntity() != null)) {
                responseBuilder.header(HttpHeaders.CONTENT_TYPE, produces.toString());
            }
            if ((responseBuilder instanceof ResponseBuilderImpl)) {
                // avoid unnecessary copying of HTTP headers from the Builder to the Response
                requestContext
                        .setResponse(
                                new LazyResponse.Existing(((ResponseBuilderImpl) responseBuilder).build(false)));
            } else {
                requestContext.setResponse(new LazyResponse.Existing(responseBuilder.build()));
            }
        } else if (result instanceof RestResponse<?> existing) {
            if (existing instanceof RestResponseImpl<?> restResponseImpl && restResponseImpl.isClientResponse()) {
                throw new IllegalStateException(
                        "A REST Client RestResponse object was returned from a server endpoint. "
                                + "This is not supported because it carries connection-specific headers "
                                + "that are not suitable for forwarding. "
                                + "Please create a new RestResponse by extracting the status, entity and headers you need.");
            }
            boolean mediaTypeAlreadyExists = false;
            //we already have a response
            //set it explicitly
            ResponseBuilderImpl responseBuilder;
            if (existing.getEntity() instanceof GenericEntity<?> genericEntity) {
                requestContext.setGenericReturnType(genericEntity.getType());
                responseBuilder = fromResponse(existing);
                responseBuilder.entity(genericEntity.getEntity());
            } else {
                //TODO: super inefficient
                responseBuilder = fromResponse(existing);
                if ((result instanceof RestResponseImpl<?> responseImpl)) {
                    // needed in order to preserve entity annotations

View on GitHub (pinned to e1c734241f)

Solutions

  1. Unwrap and rebuild: return the entity (existing.getEntity()) or a new server Response carrying extracted status/headers
  2. Use existing.readEntity(Class) to consume the body, then build a fresh Response
  3. Change the resource method's return type to the entity type rather than RestResponse
  4. If header forwarding is needed, copy selected headers explicitly into a new Response

Example fix

// before
@GET
public RestResponse<String> call() {
    return client.get(); // client RestResponse
}
// after
@GET
public Response call() {
    RestResponse<String> existing = client.get();
    return Response.ok(existing.readEntity(String.class)).build();
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (result instanceof RestResponseImpl<?> r && r.isClientResponse()) result = Response.ok(r.readEntity(Object.class)).build();

Type guard

static boolean isServerRestResponse(RestResponse<?> r) {
    return !(r instanceof org.jboss.resteasy.reactive.client.impl.RestResponseImpl<?> impl && impl.isClientResponse());
}

Try / catch

try { return proxy(); } catch (IllegalStateException e) { if (e.getMessage().contains("REST Client RestResponse")) { return Response.ok(clientResp.readEntity(String.class)).build(); } throw e; }

Prevention

When it happens

Trigger: A resource method returns the RestResponse<T> received from a MicroProfile/REST Client call, e.g. `return myClient.call();` where the client method returns RestResponse<String>.

Common situations: Service-to-service proxy endpoints; generic wrappers where RestResponse<T> is the return type both client-side and expected server-side; copy-paste between client and server APIs.

Related errors


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