Errors with @RestControllerAdvice

Spring Boot · lesson 11 of 39 · 4 min read

Turn exceptions into consistent, standard JSON error responses in one place.

Open this lesson in the learning hub

Key points

  • Throw meaningful exceptions from services. Do not return null or error codes.
  • @RestControllerAdvice holds @ExceptionHandler methods that apply across every controller.
  • Spring 6 ships ProblemDetail, the RFC 9457 error format: type, title, status, detail.
  • Never leak a stack trace or SQL text to the client. Log the full detail, return a clean message.
  • Extend ResponseEntityExceptionHandler to also reshape Spring's built-in errors, like validation failures.
  • Match the status to the cause: 400 bad input, 404 missing, 409 conflict, 500 only for genuine bugs.

Example

import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;

@RestControllerAdvice
public class ApiExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(ApiExceptionHandler.class);

    @ExceptionHandler(OrderNotFoundException.class)
    ProblemDetail notFound(OrderNotFoundException ex) {
        ProblemDetail pd = ProblemDetail.forStatusAndDetail(
                HttpStatus.NOT_FOUND, ex.getMessage());
        pd.setTitle("Order not found");
        pd.setType(URI.create("https://api.example.com/errors/order-not-found"));
        return pd;                                   // 404 + application/problem+json
    }

    @ExceptionHandler(InsufficientStockException.class)
    ProblemDetail conflict(InsufficientStockException ex) {
        ProblemDetail pd = ProblemDetail.forStatusAndDetail(
                HttpStatus.CONFLICT, "Not enough stock for " + ex.sku());
        pd.setProperty("sku", ex.sku());             // extra fields are allowed
        return pd;
    }

    @ExceptionHandler(Exception.class)
    ProblemDetail unexpected(Exception ex) {
        log.error("Unhandled error", ex);            // full detail to the log
        return ProblemDetail.forStatusAndDetail(
                HttpStatus.INTERNAL_SERVER_ERROR, "Something went wrong");
    }
}

One advice class gives your whole API a single, predictable error shape.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Boot course, and every lesson in it is listed on the Spring Boot contents page.