Bug 53337 - IllegalStateException when trying to render a JSP after startAsync
Summary: IllegalStateException when trying to render a JSP after startAsync
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 7.0.27
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2012-05-31 17:06 UTC by Rossen Stoyanchev
Modified: 2012-06-04 19:58 UTC (History)
0 users

.war demonstrating the issue (536.01 KB, application/octet-stream)
2012-05-31 17:07 UTC, Rossen Stoyanchev
Updated .war file (536.13 KB, application/octet-stream)
2012-06-01 14:44 UTC, Rossen Stoyanchev
Updated .war file (536.13 KB, application/octet-stream)
2012-06-01 14:44 UTC, Rossen Stoyanchev

Note You need to log in before you can comment on or make changes to this bug.
Description Rossen Stoyanchev 2012-05-31 17:06:36 UTC
The scenario involves:

1. ServletA forwards to Servlet B
2. ServletB calls request.startAsync and starts thread
3. New thread attempts to render a JSP

I've tried JSP rendering via asyncContext.dispatch("") and via request.getRequestDispatcher("") plus forward or include.

When using a RequestDispatcher, calling ServletA fails while calling ServletB directly succeeds. 

When using AsyncContext.dispatch, both ServletA and ServletB fail.

The exception is always the same (while attempting to render the JSP):

java.lang.IllegalStateException: Cannot create a session after the response has been committed

I've created a project at:

The project page contains instructions and attached is a .war although you might want to check the source out in order to try a couple of variations.

Beyond the specifics of the bug, the more general question is whether it is ok to use request.getRequestDispatcher from an async thread? That seems to be the case in Tomcat, aside from this bug, but in other containers (Jetty in particular) it's clearly not recommended. 

Servlet Spec discussion on this question: 
Comment 1 Rossen Stoyanchev 2012-05-31 17:07:59 UTC
Created attachment 28866 [details]
.war demonstrating the issue
Comment 2 Rossen Stoyanchev 2012-06-01 00:19:32 UTC
By the way, in the description above I only meant to refer to the methods asyncContext.dispatch and request.getRequestDispatcher. I am not actually passing "". See the link to the source code for full details.
Comment 3 Rossen Stoyanchev 2012-06-01 14:44:05 UTC
Created attachment 28873 [details]
Updated .war file
Comment 4 Rossen Stoyanchev 2012-06-01 14:44:40 UTC
Created attachment 28874 [details]
Updated .war file
Comment 5 Rossen Stoyanchev 2012-06-01 14:46:41 UTC
I corrected one issue with the sample. Calling ServletB succeeds in all cases. Calling ServletA doesn't. I updated the instructions at the project page and updated the .war attachment.
Comment 6 Mark Thomas 2012-06-03 15:58:09 UTC
The bug (forwarding to an async servlet always failed) has been fixed in trunk and 7.0.x and will be included in 7.0.28 onwards.

Re-reading the spec, it appears that the intention was that dispatches from an async thread should always be via the AsyncContext. No mention is made of dispatching via a RequestDispatcher. This is going to be one of those grey areas that different containers do different ways. I believe - but haven't tested to check all the edge cases - that in Tomcat the two would be equivalent based on which objects Tomcat uses internally. Other containers may well be different.

My personal recommendation would be to stick with dispatching via the AsyncContext.
Comment 7 Rossen Stoyanchev 2012-06-04 19:58:49 UTC
Thanks for the suggestions, Mark.

In the discussion on the servlet-spec user list, even wider implications were mentioned including avoiding reliance on the requestURI or even the session from an async thread. It's quite a surprise that none of it is mentioned in the spec.