quarkusio/quarkus · error · RuntimeException

Method ' of class ' ' cannot be used as an exception mapper…

Error message

Method '${targetMethod.name()} of class '${targetMethod.declaringClass().name()}' cannot be used as an exception mapper as it does not declare 'Response' or 'Uni<Response>' or as its return type

What it means

RESTEasy Reactive's build-time generator scans methods annotated with @ServerExceptionMapper / @Provider and requires a supported return type: 'Response', 'RestResponse', 'Uni<Response>' (or Uni<RestResponse>). In determineReturnType, if no branch matches the method's return type, a RuntimeException is thrown, aborting application build. This enforces that exception mappers actually produce an HTTP response that can be returned to the client.

Solutions

  1. Change the mapper method return type to jakarta.ws.rs.core.Response
  2. Or return io.smallrye.mutiny.Uni<Response> for asynchronous mapping
  3. Or return jakarta.ws.rs.core.RestResponse if using the RESTEasy Reactive API
  4. Remove @ServerExceptionMapper/@Provider from methods that are not intended to be exception mappers

Example fix

// before
@ServerExceptionMapper
public String map(IllegalStateException e) { return e.getMessage(); }

// after
@ServerExceptionMapper
public Response map(IllegalStateException e) { return Response.status(500).entity(e.getMessage()).build(); }
Defensive patterns

Strategy: validation

Validate before calling

java.lang.reflect.Method m = ...; // the annotated mapper
boolean ok = Response.class.equals(m.getReturnType())
    || RestResponse.class.equals(m.getReturnType())
    || (m.getReturnType() == Uni.class && m.getGenericReturnType() instanceof ParameterizedType pt
        && Response.class.equals(pt.getActualTypeArguments()[0]));
if (!ok) throw new IllegalStateException("Mapper must return Response, RestResponse, or Uni<Response>: " + m);

Type guard

static boolean isValidMapperReturn(java.lang.reflect.Method m) {
    return Response.class.equals(m.getReturnType()) || RestResponse.class.equals(m.getReturnType())
        || (m.getReturnType() == Uni.class
            && m.getGenericReturnType() instanceof ParameterizedType pt
            && (Response.class.equals(pt.getActualTypeArguments()[0]) || RestResponse.class.equals(pt.getActualTypeArguments()[0])));
}

Prevention

When it happens

Trigger: Annotating a method with @ServerExceptionMapper (or @Provider recognized as a server exception mapper) whose return type is anything other than Response, RestResponse, Uni<Response>, or Uni<RestResponse> — e.g. void, String, MyPojo, CompletionStage<Response> — triggers the error during Quarkus augmentation.

Common situations: Developers migrating from classic JAX-RS ExceptionMapper semantics, writing a mapper that logs and returns void, returning a custom DTO instead of Response, or accidentally annotating an ordinary helper method with @Provider in a scanned package.

Related errors


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

Appendix: source

Thrown at independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/exceptionmappers/ServerExceptionMapperGenerator.java:634

    }

    private static ReturnType determineReturnType(MethodInfo targetMethod) {
        if (targetMethod.returnType().name().equals(RESPONSE)) {
            return ReturnType.RESPONSE;
        } else if (targetMethod.returnType().name().equals(REST_RESPONSE)) {
            return ReturnType.REST_RESPONSE;
        } else if (targetMethod.returnType().kind() == Type.Kind.PARAMETERIZED_TYPE) {
            ParameterizedType parameterizedType = targetMethod.returnType().asParameterizedType();
            if (parameterizedType.name().equals(UNI) && (parameterizedType.arguments().size() == 1)) {
                if (parameterizedType.arguments().get(0).name().equals(RESPONSE)) {
                    return ReturnType.UNI_RESPONSE;
                }
                if (parameterizedType.arguments().get(0).name().equals(REST_RESPONSE)) {
                    return ReturnType.UNI_REST_RESPONSE;
                }
            }
        }
        throw new RuntimeException("Method '" + targetMethod.name() + " of class '" + targetMethod.declaringClass().name()
                + "' cannot be used as an exception mapper as it does not declare 'Response' or 'Uni<Response>' or as its return type");
    }

    private static void checkModifiers(MethodInfo info) {
        if ((info.flags() & Modifier.PRIVATE) != 0) {
            throw new RuntimeException("Method '" + info.name() + " of class '" + info.declaringClass().name()
                    + "' cannot be private as it is annotated with '@" + SERVER_EXCEPTION_MAPPER
                    + "'");
        }
        if ((info.flags() & Modifier.STATIC) != 0) {
            throw new RuntimeException("Method '" + info.name() + " of class '" + info.declaringClass().name()
                    + "' cannot be static as it is annotated with '@" + SERVER_EXCEPTION_MAPPER
                    + "'");
        }
    }

    private static String getGeneratedClassName(MethodInfo targetMethod, Type handledExceptionType) {
        return targetMethod.declaringClass().name() + "$ExceptionMapper$"

View on GitHub (pinned to e1c734241f)