Skip to Content
Jora K

4 mins read


Why does Spring Boot return a 500 Internal Error status instead of 404 after an update

Understanding why after updating Spring to version 6.1+ in a Java application, a 500 Internal Error occurs instead of the expected 404 Not Found for non-existent API calls and how to fix it.


Intro

In this note, we will discuss why a 500 Internal Error occurs instead of the expected 404 Not Found after updating Spring or Spring Boot in a Java application and how to fix it. This article addresses errors when updating to Spring 6.1+ and Spring Boot 3.2+ from earlier versions.

What could go wrong?

After updating the version of Spring or Spring Boot in your application, you may notice that when requesting a non-existent resource, a 500 Internal Error is returned instead of the expected 404 status as it was before:

{
  "timestamp": "2024-10-22T12:34:56.789Z",
  "status": 404,
  "error": "Not Found",
  "path": "/adabracadabra"
}

In Spring 6.1+ and Spring Boot 3.2+, a change was made to the behavior of handling the NoResourceFoundException in the ResourceHttpRequestHandler class. Now this exception is handled not by Spring, but by the error handler defined by the developer.

A standard practice is to use the @ExceptionHandler annotation to handle exceptions in controllers, and in case of an unexpected error, return a 500 status. For example, in your code, you might have a default handler like this:

@ExceptionHandler(Exception.class)
public ResponseEntity handleAll(Exception ex, WebRequest request) {
    log.error(ex.getMessage(), ex);
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}

When any exception occurs in the application, this method intercepts it, logs it, and returns a response with a 500 status code and an error message. In the new version of Spring, NoResourceFoundException also gets caught by this handler, and instead of the standard 404, a 500 status is returned.

How to fix it?

To fix this issue, you need to add an exception handler for NoResourceFoundException in the controller and return a 404 status, or create a separate exception handler for NoResourceFoundException:

import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.resource.NoResourceFoundException;
 
import java.time.Instant;
 
@Slf4j
@ControllerAdvice
public class CustomExceptionHandler {
    // ...
 
    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseEntity<CustomErrorResource> handleNoResourceFoundException(NoResourceFoundException exception) {
        log.error("Resource not found", exception);
        CustomErrorResource resource = CustomErrorResource.builder()
                .timestamp(Instant.now().toString())
                .status(exception.getStatusCode().value())
                .error(exception.getMessage())
                .path(exception.getResourcePath())
                .build();
        return ResponseEntity
                .status(exception.getStatusCode())
                .body(resource);
    }
 
    @Data
    @Builder
    public static class CustomErrorResource {
        private String timestamp;
        private int status;
        private String error;
        private String path;
    }
 
    // ...
}
 

Now the error status and response body return to their previous state.
PROFIT!