{"record":{"id":"6874ca1018fcafe3","repo":"quarkusio/quarkus","slug":"exceptionhandler-methods-in-controlleradvice-cla","errorCode":null,"errorMessage":"@ExceptionHandler methods in @ControllerAdvice classes can only have void, ResponseEntity or POJO return types","messagePattern":"@ExceptionHandler methods in @ControllerAdvice classes can only have void, ResponseEntity or POJO return types","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java","lineNumber":222,"sourceCode":"            return;\n        }\n\n        ClassInfo controllerAdvice = controllerAdviceInstance.target().asClass();\n        List<MethodInfo> methods = controllerAdvice.methods();\n        for (MethodInfo method : methods) {\n            AnnotationInstance exceptionHandlerInstance = method.annotation(EXCEPTION_HANDLER);\n            if (exceptionHandlerInstance == null) {\n                continue;\n            }\n\n            if (!Modifier.isPublic(method.flags()) || Modifier.isStatic(method.flags())) {\n                throw new IllegalStateException(\n                        \"@ExceptionHandler methods in @ControllerAdvice must be public instance methods\");\n            }\n\n            DotName returnTypeDotName = method.returnType().name();\n            if (DISALLOWED_EXCEPTION_CONTROLLER_RETURN_TYPES.contains(returnTypeDotName)) {\n                throw new IllegalStateException(\n                        \"@ExceptionHandler methods in @ControllerAdvice classes can only have void, ResponseEntity or POJO return types\");\n            }\n\n            if (!RESPONSE_ENTITY.equals(returnTypeDotName)) {\n                reflectiveClassProducer.produce(\n                        ReflectiveClassBuildItem.builder(returnTypeDotName.toString()).methods().fields().build());\n            }\n\n            // we need to generate one JAX-RS ExceptionMapper per Exception type\n            Type[] handledExceptionTypes = exceptionHandlerInstance.value().asClassArray();\n            for (Type handledExceptionType : handledExceptionTypes) {\n                reflectiveClassProducer.produce(\n                        ReflectiveClassBuildItem.builder(method.declaringClass().toString()).constructors(false).build());\n                String name = new ControllerAdviceExceptionMapperGenerator(method, handledExceptionType.name(),\n                        classOutput, typesUtil, isResteasyClassic).generate();\n                providersProducer.produce(new ResteasyJaxrsProviderBuildItem(name));\n                exceptionMapperProducer.produce(\n                        new ExceptionMapperBuildItem(name, handledExceptionType.name().toString(), Priorities.USER, false));","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java#L204-L240","documentation":"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.","triggerScenarios":"An @ExceptionHandler method in a @ControllerAdvice returns a type like ModelAndView, Model, View, or another disallowed Spring web type.","commonSituations":"Migrating Spring MVC code that renders views (Thymeleaf/JSP style) to Quarkus; handlers returning raw Servlet objects copied from legacy code.","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."],"exampleFix":"// before\n@ExceptionHandler(MyException.class)\npublic ModelAndView handle(MyException e) { return new ModelAndView(\"error\"); }\n\n// after\n@ExceptionHandler(MyException.class)\npublic ResponseEntity<ErrorDto> handle(MyException e) {\n  return ResponseEntity.status(422).body(new ErrorDto(e.getMessage()));\n}","handlingStrategy":"validation","validationCode":"// allowed return types: void, ResponseEntity<T>, serializable POJO\n// reject at code review: ModelAndView, Model, View, Servlet objects","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Return ResponseEntity<T> or JSON DTOs from @ExceptionHandler methods.","Search migrated Spring code for view-layer return types before porting."],"tags":["quarkus","spring-web","return-type","build-time"],"backgroundTag":"unsupported-return-type","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}