Skip to content

"IllegalStateException: Cannot call sendError() after the response has been committed" when IOException is thrown during resolving method argument values on Tomcat >= 10.1.16 #32206

Closed
@mgocd

Description

@mgocd

Affects: Spring Framework 6.1.3 with Tomcat >= 10.1.16 (or Spring Boot >= 3.1.6, including 3.2.x)

Description

When an IOException is thrown during resolving method argument values for a Rest Controller (in Tomcat's InputBuffer#realReadBytes#313, invoked by Spring's AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters#174), Spring's DefaultHandlerExceptionResolver#handleHttpMessageNotReadable:587 throws an IllegalStateException with message Cannot call sendError() after the response has been committed.

This also results in setting HTTP response status code to 500 instead of 400.

In Spring Framework 6.1.3 with Tomcat 10.1.15 the IllegalStateException is not thrown, and the HTTP status code is 400.

Reproduction

See https://github.com/mgocd/spring-httpmessagenotreadableexception-resolve-issue

Analysis

Starting from Tomcat 10.1.16 (because of this commit) the exception handler inside InputBuffer#realReadBytes runs response.sendError(400), making the httpServletResponse.isCommitted() return true starting from this point.

When Spring's DefaultHandlerExceptionResolver#handleHttpMessageNotReadable:587 runs response.sendError(400) again, it throws the IllegalStateException: Cannot call sendError() after the response has been committed.

To resolve the issue, DefaultHandlerExceptionResolver#handleHttpMessageNotReadable could run response.sendError conditionally, only if !response.isCommitted(), similarly as done in DefaultHandlerExceptionResolver#handleErrorResponse:514.

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: backportedAn issue that has been backported to maintenance branchestype: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions