Global exception handling is one of the most important features in any Spring Boot REST API. Instead of returning stack traces or inconsistent error responses, it allows you to handle exceptions in one central location using @ControllerAdvice and @ExceptionHandler.
However, many developers encounter situations where global exception handling simply doesn’t work.
Common symptoms include:
- Your
@ExceptionHandlermethod is never called. - Spring Boot returns the default Whitelabel Error Page.
- HTTP 500 responses appear instead of your custom error message.
- Validation exceptions bypass your global handler.
- Exceptions thrown from filters or security are not intercepted.
This guide explains how Spring Boot exception handling works internally, the most common reasons it fails, and production-ready solutions to fix it.
Table of Contents
- What is Global Exception Handling?
- How Spring Boot Processes Exceptions
- Why Global Exception Handling Stops Working
- Common Production Issues
- Best Practices
- Frequently Asked Questions
What Is Global Exception Handling?
Instead of surrounding every controller method with try-catch blocks, Spring Boot allows centralized exception handling.
Example:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handle(UserNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ex.getMessage());
}
}
Whenever UserNotFoundException is thrown, Spring automatically calls the matching handler.
If you’re new to REST APIs, first read:
REST API Basics in Spring Boot
How Spring Boot Handles Exceptions
The request lifecycle looks like this:
Client Request
│
▼
Filter
│
▼
DispatcherServlet
│
▼
Controller
│
▼
Service
│
▼
Repository
│
Exception Occurs
▼
@ControllerAdvice
│
▼
HTTP Response
Understanding the request lifecycle makes exception handling much easier.
Read:
Request Lifecycle in Spring Boot – From Client to Response
Common Cause 1 — Missing @RestControllerAdvice
Incorrect:
public class GlobalExceptionHandler {
}
Correct:
@RestControllerAdvice
public class GlobalExceptionHandler {
}
For REST APIs, prefer @RestControllerAdvice because it automatically returns JSON responses.
Common Cause 2 — Missing @ExceptionHandler
Incorrect:
public ResponseEntity<String> handle(Exception ex) {
}
Correct:
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handle(Exception ex) {
}
Without the annotation, Spring never registers the method.
Common Cause 3 — Exception Never Reaches Controller
Many developers expect every exception to be handled by @ControllerAdvice.
This is incorrect.
Exceptions thrown inside:
- Servlet Filters
- Spring Security Filters
- Tomcat
- Embedded Server
never reach the controller layer.
Example:
public class JwtFilter extends OncePerRequestFilter {
}
Exceptions here require filter-level handling.
Common Cause 4 — Wrong Exception Type
Example:
@ExceptionHandler(RuntimeException.class)
but the application throws:
MethodArgumentNotValidException
The handler never matches.
Always verify the actual exception from logs.
Enable debug logging if needed.
Read:
How to Enable Debug Logging in Spring Boot
Common Cause 5 — Package Scanning Issue
If your exception handler is outside the package scanned by Spring Boot, it won’t be detected.
Correct structure:
com.company
├── Application.java
├── controller
├── service
├── repository
├── exception
Understanding startup scanning helps here.
Read:
How Spring Boot Application Starts (Startup Flow Explained)
Common Cause 6 — Validation Exceptions Not Handled
Validation errors use a different exception:
MethodArgumentNotValidException
Example:
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleValidation(MethodArgumentNotValidException ex){
}
Without this handler, Spring returns its default validation response.
Common Cause 7 — Returning Wrong Response Type
Avoid:
return "Error";
Prefer:
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(errorResponse);
Returning structured JSON makes APIs consistent and easier to consume.
Creating a Standard Error Response
Example DTO:
public class ErrorResponse {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}
Example response:
{
"timestamp":"2026-07-20T10:30:00",
"status":404,
"error":"Not Found",
"message":"User not found",
"path":"/users/10"
}
This format is much easier for frontend applications to consume.
Production Best Practices
For reliable exception handling:
- Use
@RestControllerAdvicefor REST APIs. - Handle business exceptions separately from system exceptions.
- Return meaningful HTTP status codes.
- Never expose stack traces to clients.
- Log exceptions before returning responses.
- Use a standard error response model.
- Create custom exceptions for business rules.
Common Exceptions You Should Handle
Most production applications should include handlers for:
MethodArgumentNotValidExceptionIllegalArgumentExceptionAccessDeniedExceptionEntityNotFoundExceptionHttpMessageNotReadableExceptionDataIntegrityViolationExceptionConstraintViolationException- Generic
Exception
Related Spring Boot Guides
REST API Basics in Spring Boot
Request Lifecycle in Spring Boot
Spring Boot Annotations – Complete List
BeanCreationException – Common Causes and Fixes
Spring Boot Auto-Configuration Explained
Enable Debug Logging in Spring Boot
Frequently Asked Questions
Why is my @ExceptionHandler not being called?
The most common reasons are:
- Missing
@RestControllerAdvice - Missing
@ExceptionHandler - Wrong exception type
- Package scanning issue
- Exception thrown before reaching the controller
Does @ControllerAdvice catch exceptions from filters?
No. Exceptions thrown in servlet filters or Spring Security filters must be handled separately because they occur before the request reaches the controller.
Should I catch every exception globally?
Handle expected business exceptions individually and include a generic Exception handler as a fallback. Avoid exposing internal implementation details to clients.
Summary
Global exception handling improves the consistency, security, and maintainability of Spring Boot applications, but it only works when exceptions reach the Spring MVC layer and are mapped correctly. By understanding the request lifecycle, using @RestControllerAdvice, handling the correct exception types, and returning structured error responses, you can build production-ready REST APIs that are easier to debug and safer for clients to consume.
