ModelAndView not displaying from ExceptionHandler

In spring boot 3.3.3 I’m trying to use the default HandlerExceptionResolver to capture any exceptions that happen in the security filter chain to process them inside the same ExceptHandler ControllerAdvise that controllers use. I can see the exception making it all the way to the inside of the ExceptionHandler but nothing every happens with the returned modelAndView. The browser shows a blank page.

To test this, I have a sample filter wherein I throw an exception when a specific URI is encountered:

@Slf4j
public class SampleFilter extends OncePerRequestFilter {

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    log.debug( "entered SampleFilter" );
    if ( request.getRequestURI().endsWith("does-not-exist") ) {
      log.debug( "throwing exception" );
      throw new SampleException("does-not-exist does not exist!  Big surprise!");
    }
    filterChain.doFilter(request, response);
  }

}

another filter catches all exceptions and sends them to the resolver

@Slf4j
@Component
public class FilterChainExceptionHandlerFilter  extends OncePerRequestFilter {

  @Autowired
  @Qualifier("handlerExceptionResolver")
  private HandlerExceptionResolver resolver;

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    try {
      filterChain.doFilter(request, response);
    } catch (Exception e) {
      log.error("Spring Security Filter Chain Exception:", e);
      resolver.resolveException(request, response, null, e);
    }
  }
}

I register these in the securityFilterChain

@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig {

  @Autowired
  private FilterChainExceptionHandlerFilter filterChainExceptionHandlerFilter;

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
            .csrf(AbstractHttpConfigurer::disable)
            .formLogin(AbstractHttpConfigurer::disable)
            .httpBasic(AbstractHttpConfigurer::disable)
            .anonymous(AbstractHttpConfigurer::disable)
            .logout(AbstractHttpConfigurer::disable)
            .addFilterBefore( filterChainExceptionHandlerFilter, DisableEncodeUrlFilter.class )
            .addFilterBefore( new SampleFilter(), SecurityContextHolderFilter.class )
            .build();
  }

}

I define an ExceptionHandler specific for the thrown exception in ControllerAdvice

@Slf4j
@ControllerAdvice
public class ExceptionController {

  @ExceptionHandler( {SampleException.class} )
  public ModelAndView handleSampleException(HttpServletRequest req, Exception e) {
    log.debug( "SampleException: setup error page for " + e.getLocalizedMessage() );
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("error");
    modelAndView.addObject( "message", e.getLocalizedMessage() );
    return modelAndView;
  }

}

It SHOULD then get picked up by the error controller

@Slf4j
@Controller
public class SampleErrorController implements ErrorController {

  @RequestMapping( "/error" )
  public String showError( HttpServletRequest request,
                           Model model ) {
    Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
    if (status != null) {
      Integer statusCode = Integer.valueOf(status.toString());
      model.addAttribute( "statusCode", statusCode );
    }

    return "error";
  }

}

and sent on to the simple error.html Thymeleaf template I have.

Entering a URL that doesn’t exist and doesn’t throw an exception from the SampleFilter gets sent to the template just fine. I see my exception get logged in the ExceptionHandler methods, but the ModelAndView never seems to get passed on to Thymeleaf.

Log

 :: Spring Boot ::                (v3.3.3)

2024-09-22 15:30:51,778 INFO  [restartedMain] o.s.b.StartupInfoLogger: Starting SampleApplication using Java 17.0.12 with PID 3084906 (/home/user/github/spring-servlet-filter-exception/target/classes started by user in /home/user/github/spring-servlet-filter-exception)
2024-09-22 15:30:51,779 DEBUG [restartedMain] o.s.b.StartupInfoLogger: Running with Spring Boot v3.3.3, Spring v6.1.12
2024-09-22 15:30:51,780 INFO  [restartedMain] o.s.b.SpringApplication: No active profile set, falling back to 1 default profile: "default"
2024-09-22 15:30:52,503 DEBUG [restartedMain] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver: ControllerAdvice beans: 1 @ExceptionHandler, 1 ResponseBodyAdvice
2024-09-22 15:30:52,543 DEBUG [restartedMain] o.s.w.f.GenericFilterBean: Filter 'filterChainExceptionHandlerFilter' configured for use
2024-09-22 15:30:52,575 WARN  [restartedMain] o.s.b.a.s.s.UserDetailsServiceAutoConfiguration: 

Using generated security password: d4c20939-34c6-4bc1-ab92-c176e0cba968

This generated password is for development use only. Your security configuration must be updated before running your application in production.

2024-09-22 15:30:52,598 INFO  [restartedMain] o.s.s.c.a.a.c.InitializeUserDetailsBeanManagerConfigurer$InitializeUserDetailsManagerConfigurer: Global AuthenticationManager configured with UserDetailsService bean with name inMemoryUserDetailsManager
2024-09-22 15:30:52,673 DEBUG [restartedMain] o.s.w.s.h.AbstractHandlerMethodMapping: 2 mappings in 'requestMappingHandlerMapping'
2024-09-22 15:30:52,689 DEBUG [restartedMain] o.s.w.s.h.SimpleUrlHandlerMapping: Patterns [/webjars/**, /**] in 'resourceHandlerMapping'
2024-09-22 15:30:52,708 DEBUG [restartedMain] o.s.s.w.DefaultSecurityFilterChain: Will secure any request with filters: FilterChainExceptionHandlerFilter, DisableEncodeUrlFilter, WebAsyncManagerIntegrationFilter, SampleFilter, SecurityContextHolderFilter, HeaderWriterFilter, RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter, ExceptionTranslationFilter
2024-09-22 15:30:52,727 WARN  [restartedMain] o.s.s.c.a.w.b.WebSecurity: 

********************************************************************
**********        Security debugging is enabled.       *************
**********    This may include sensitive information.  *************
**********      Do not use in a production system!     *************
********************************************************************


2024-09-22 15:30:52,764 DEBUG [restartedMain] o.s.w.s.m.m.a.RequestMappingHandlerAdapter: ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
2024-09-22 15:30:52,852 INFO  [restartedMain] o.s.b.StartupInfoLogger: Started SampleApplication in 1.326 seconds (process running for 1.697)
2024-09-22 15:31:39,910 INFO  [http-nio-8080-exec-1] o.s.w.s.FrameworkServlet: Initializing Servlet 'dispatcherServlet'
2024-09-22 15:31:39,910 DEBUG [http-nio-8080-exec-1] o.s.w.s.DispatcherServlet: Detected StandardServletMultipartResolver
2024-09-22 15:31:39,911 DEBUG [http-nio-8080-exec-1] o.s.w.s.DispatcherServlet: Detected AcceptHeaderLocaleResolver
2024-09-22 15:31:39,911 DEBUG [http-nio-8080-exec-1] o.s.w.s.DispatcherServlet: Detected FixedThemeResolver
2024-09-22 15:31:39,912 DEBUG [http-nio-8080-exec-1] o.s.w.s.DispatcherServlet: Detected org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator@35c882e0
2024-09-22 15:31:39,912 DEBUG [http-nio-8080-exec-1] o.s.w.s.DispatcherServlet: Detected org.springframework.web.servlet.support.SessionFlashMapManager@5e3d86ed
2024-09-22 15:31:39,912 DEBUG [http-nio-8080-exec-1] o.s.w.s.FrameworkServlet: enableLoggingRequestDetails='true': request parameters and headers will be shown which may lead to unsafe logging of potentially sensitive data
2024-09-22 15:31:39,912 INFO  [http-nio-8080-exec-1] o.s.w.s.FrameworkServlet: Completed initialization in 2 ms
2024-09-22 15:31:39,940 DEBUG [http-nio-8080-exec-1] o.s.s.w.FilterChainProxy: Securing GET /does-not-exist
2024-09-22 15:31:39,943 DEBUG [http-nio-8080-exec-1] o.e.s.SampleFilter: entered SampleFilter
2024-09-22 15:31:39,944 DEBUG [http-nio-8080-exec-1] o.e.s.SampleFilter: throwing exception
2024-09-22 15:31:39,944 ERROR [http-nio-8080-exec-1] o.e.s.FilterChainExceptionHandlerFilter: Spring Security Filter Chain Exception:
org.example.controller.SampleException: does-not-exist does not exist!  Big surprise!
    at org.example.security.SampleFilter.doFilterInternal(SampleFilter.java:21)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    at org.example.security.FilterChainExceptionHandlerFilter.doFilterInternal(FilterChainExceptionHandlerFilter.java:27)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
    at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:90)
    at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:78)
    at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:67)
    at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    at org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
    at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
    at org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:230)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
    at java.base/java.lang.Thread.run(Thread.java:840)
2024-09-22 15:31:39,948 DEBUG [http-nio-8080-exec-1] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver: Using @ExceptionHandler org.example.controller.ExceptionController#handleSampleException(HttpServletRequest, Exception)
2024-09-22 15:31:39,950 DEBUG [http-nio-8080-exec-1] o.e.c.ExceptionController: SampleException: setup error page for does-not-exist does not exist!  Big surprise!
2024-09-22 15:31:39,958 WARN  [http-nio-8080-exec-1] o.s.w.s.h.AbstractHandlerExceptionResolver: Resolved [org.example.controller.SampleException: does-not-exist does not exist!  Big surprise!]

It stops there and no error page is rendered.

This entire sample can be run

$ get clone https://github.com/smaring/spring-servlet-filter-exception.git
$ cd spring-servlet-filter-exception
$ mvn clean spring-boot:run

and opening a browser to http://localhost:8080/does-not-exist

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật