I wrote a custom exception handler for JSF to log the exception and navigate to an error page to be shown to the user. Unfortunately, I get a IllegalStateException \"Cannot
The exception being handled is apparently been thrown during render response phase, at that point when the HTTP response is already been committed. A committed response means that the first part of the HTTP response, including the headers, is already been sent to the client side. This is a point of no return. You can't take the already sent bytes back from the client.
A response will usually be auto-committed when the written content exceeds the buffer size which defaults usually to ~2KB, depending on servletcontainer and Facelets configuration. The average HTML occuppies already 1~2KB. So the change is big that the response is already committed before JSF starts to render the
or only a small part of it.
In your particular case there's however one more cause: when you receive more than one unhandled exception, then you will also run into trouble, because you're not aborting the while
loop after having navigated, but continuing to handling the next exception. You can't return multiple responses (error pages) to a single request. You should either collect all exceptions and navigate only once, or to abort the loop after the first one.
In any case, handling exceptions which are thrown during render response is only possible as long as the response is not (auto)-committed. You can try several approaches to prevent the response from being auto committed too soon:
Set the Facelets buffer size to the size of your largest HTML response. E.g. 64KB:
javax.faces.FACELETS_BUFFER_SIZE
65535
Perform the exception-sensitive business job before rendering the view (i.e. don't do it in (post)constructor of a bean which is constructed during a GET request):
As to handling with exceptions in JSF in general, you may find OmniFaces FullAjaxExceptionHandler helpful. You can find its source code here.