Bug 63816

Summary: java.lang.IllegalStateException: Calling [asyncMustError()] is not valid for a request with Async state [STARTING]
Product: Tomcat 9 Reporter: Alex <a701440>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P2    
Version: 9.0.22   
Target Milestone: -----   
Hardware: PC   
OS: Linux   

Description Alex 2019-10-08 16:52:41 UTC
After starting async processing request.startAsync() for the request a background thread invokes the response write functions. Sometimes when IO errors happen I get the exception below.


java.lang.IllegalStateException: Calling [asyncMustError()] is not valid for a request with Async state [STARTING]
java.lang.IllegalStateException: Calling [asyncMustError()] is not valid for a request with Async state [STARTING]
	at org.apache.coyote.AsyncStateMachine.asyncMustError(AsyncStateMachine.java:421)
	at org.apache.coyote.AbstractProcessor.setErrorState(AbstractProcessor.java:118)
	at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:424)
	at org.apache.coyote.Response.action(Response.java:211)
	at org.apache.coyote.http11.Http11OutputBuffer$SocketOutputBuffer.doWrite(Http11OutputBuffer.java:546)
	at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:112)
	at org.apache.coyote.http11.Http11OutputBuffer.doWrite(Http11OutputBuffer.java:190)
	at org.apache.coyote.Response.doWrite(Response.java:599)
	at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:329)
Comment 1 Mark Thomas 2019-10-08 18:46:01 UTC
Please provide the full stack trace and as much detail as you can on the conditions that trigger the error.
Comment 2 Mark Thomas 2019-10-08 21:47:26 UTC
I've been able to create a test case for this.

This is one of those areas of the Servlet spec that could benefit from some clarification. There is this text in the spec:

<quote>
The application is responsible to handle concurrent access to the request and response objects if the async task is executing before the container-initiated dispatch that called startAsync has returned to the container.
</quote>

Does this mean that the dispatching servlet should exit to service() method immediately after calling startAsync(). I'd argue that that is good practice implied by the above quote but not required.

Does this mean that the async thread should take steps not to use the request and response objects until it knows the service() method has returned? That is certainly the safest interpretation of "handle concurrent access" but it isn't the only one.

Tomcat already handles the case where complete() or dispatch() are called on the async thread before the service() method exists. We "just" need to handle the error case in the same way.

It looks like this ASCII art is going to need to be updated:
https://github.com/apache/tomcat/blob/master/java/org/apache/coyote/AsyncStateMachine.java#L78
Comment 3 Alex 2019-10-08 22:07:39 UTC
I also filed https://bz.apache.org/bugzilla/show_bug.cgi?id=63817 for a similar problem, so may be the fix can be for both together?
Comment 4 Mark Thomas 2019-10-14 16:58:45 UTC
Fixed in:
- master for 9.0.28 onwards
- 8.5.x for 8.5.48 onwards
- 7.0.x for 7.0.98 onwards