quarkusio/quarkus · error · IllegalStateException
@ExceptionHandler methods in @ControllerAdvice classes can o
Error message
@ExceptionHandler methods in @ControllerAdvice classes can only have void, ResponseEntity or POJO return types
What it means
The generated JAX-RS ExceptionMapper must know how to write the response body. @ExceptionHandler methods returning unsupported types (per DISALLOWED_EXCEPTION_CONTROLLER_RETURN_TYPES, e.g. Spring Model/View types Quarkus can't render) are rejected at build time. Only void, ResponseEntity, or serializable POJO return types are supported.
Source
Thrown at extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java:222
return;
}
ClassInfo controllerAdvice = controllerAdviceInstance.target().asClass();
List<MethodInfo> methods = controllerAdvice.methods();
for (MethodInfo method : methods) {
AnnotationInstance exceptionHandlerInstance = method.annotation(EXCEPTION_HANDLER);
if (exceptionHandlerInstance == null) {
continue;
}
if (!Modifier.isPublic(method.flags()) || Modifier.isStatic(method.flags())) {
throw new IllegalStateException(
"@ExceptionHandler methods in @ControllerAdvice must be public instance methods");
}
DotName returnTypeDotName = method.returnType().name();
if (DISALLOWED_EXCEPTION_CONTROLLER_RETURN_TYPES.contains(returnTypeDotName)) {
throw new IllegalStateException(
"@ExceptionHandler methods in @ControllerAdvice classes can only have void, ResponseEntity or POJO return types");
}
if (!RESPONSE_ENTITY.equals(returnTypeDotName)) {
reflectiveClassProducer.produce(
ReflectiveClassBuildItem.builder(returnTypeDotName.toString()).methods().fields().build());
}
// we need to generate one JAX-RS ExceptionMapper per Exception type
Type[] handledExceptionTypes = exceptionHandlerInstance.value().asClassArray();
for (Type handledExceptionType : handledExceptionTypes) {
reflectiveClassProducer.produce(
ReflectiveClassBuildItem.builder(method.declaringClass().toString()).constructors(false).build());
String name = new ControllerAdviceExceptionMapperGenerator(method, handledExceptionType.name(),
classOutput, typesUtil, isResteasyClassic).generate();
providersProducer.produce(new ResteasyJaxrsProviderBuildItem(name));
exceptionMapperProducer.produce(
new ExceptionMapperBuildItem(name, handledExceptionType.name().toString(), Priorities.USER, false));View on GitHub (pinned to e1c734241f)
Solutions
- Change the return type to ResponseEntity<T> or a plain POJO that Jackson can serialize.
- Return void if the response body isn't needed (status from @ResponseStatus or the exception).
- Replace view-model logic with building a JSON DTO and returning it via ResponseEntity.
Example fix
// before
@ExceptionHandler(MyException.class)
public ModelAndView handle(MyException e) { return new ModelAndView("error"); }
// after
@ExceptionHandler(MyException.class)
public ResponseEntity<ErrorDto> handle(MyException e) {
return ResponseEntity.status(422).body(new ErrorDto(e.getMessage()));
} Defensive patterns
Strategy: validation
Validate before calling
// allowed return types: void, ResponseEntity<T>, serializable POJO // reject at code review: ModelAndView, Model, View, Servlet objects
Prevention
- Return ResponseEntity<T> or JSON DTOs from @ExceptionHandler methods.
- Search migrated Spring code for view-layer return types before porting.
When it happens
Trigger: An @ExceptionHandler method in a @ControllerAdvice returns a type like ModelAndView, Model, View, or another disallowed Spring web type.
Common situations: Migrating Spring MVC code that renders views (Thymeleaf/JSP style) to Quarkus; handlers returning raw Servlet objects copied from legacy code.
Related errors
- ${method.name()} of Repository ${repositoryClassInfo} is mea
- of Repository
- Parameter type <type> is being used multiple times in method
- Parameter type <type> is not supported for method<method> of
- Parameter type '<type>' is not supported for method '<method
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/6874ca1018fcafe3.
Report an issue: GitHub.