Skip to content

Incorrect AsyncRequestTimeoutException handling in ResponseEntityExceptionHandler #32644

@lexakimov

Description

@lexakimov

Affects: 6.1.5

Hello. I noticed that when using the RFC7807 error handler, the AsyncRequestTimeoutException is not handled correctly.

The org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler class handles this exception:

else if (ex instanceof AsyncRequestTimeoutException subEx) { return handleAsyncRequestTimeoutException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request); }

however, the getBody() method in the exception itself always returns a new object:

@Override public ProblemDetail getBody() { return ProblemDetail.forStatus(getStatusCode()); }

Because of this, populating the fields in the org.springframework.web.ErrorResponse#updateAndGetBody method (that called from org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler#handleExceptionInternal) has no effect.

Reproduction:

  • enable a rfc7807 handler: spring.mvc.problemdetails.enabled: true.
  • add custom messages to default message source
# AsyncRequestTimeoutException problemDetail.type.org.springframework.web.context.request.async.AsyncRequestTimeoutException=about:blank problemDetail.title.org.springframework.web.context.request.async.AsyncRequestTimeoutException=request timeout problemDetail.org.springframework.web.context.request.async.AsyncRequestTimeoutException=timeout reached
  • create controller and throw exception like this:
 @GetMapping("/springError/AsyncRequestTimeoutException") public TestResponseDto asyncRequestTimeoutException() { throw new AsyncRequestTimeoutException(); }

we expect to see a response like this:

{ "type": "about:blank", "title": "request timeout", "status": 500, "detail": "timeout reached", "instance": "/api/test/springError/AsyncRequestTimeoutException" }

but in fact the response is:

{ "type": "about:blank", "title": "Service Unavailable", "status": 503, "instance": "/api/test/springError/AsyncRequestTimeoutException" }

Suggestion

I guess it can be fixed in AsyncRequestTimeoutException like that:

private final ProblemDetail body = ProblemDetail.forStatus(getStatusCode()); ... @Override public ProblemDetail getBody() { return this.body;	}

Workaround
as a workaround, i overridden method ru.wbbank.error.handler.starter.webmvc.controller.WBProblemDetailsExceptionHandler#handleAsyncRequestTimeoutException.

We create problemDetail manually, not by AsyncRequestTimeoutException:

 @Override protected ResponseEntity<Object> handleAsyncRequestTimeoutException( AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request ) { var problemDetail = ProblemDetail.forStatus(HttpStatus.INTERNAL_SERVER_ERROR); var errResp = ErrorResponse.builder(ex, problemDetail).build(); problemDetail = errResp.updateAndGetBody(getMessageSource(), LocaleContextHolder.getLocale()); return this.handleExceptionInternal(ex, problemDetail, errResp.getHeaders(), errResp.getStatusCode(), request); }

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