@ExceptionHandler in Spring MVC — Handling Specific Exceptions
Fast recall
Quick revision
Core answer
Understanding the mechanics of exception handling in Spring MVC and how to map exceptions to HTTP responses
Putting @ExceptionHandler inside a @RestController thinking it's global — it only applies to that one controller
Clearly explain the difference between local (inside @RestController) and global (inside @ControllerAdvice) scope of @ExceptionHandler
Interview-ready guide
Interview answer
For example, a local @ExceptionHandler(ReportFormatException.class) can serve one report controller, while a global handler for OrderNotFoundException can keep every order endpoint's 404 body consistent. A separate handler for Exception should be added only if it logs and preserves a correct 500 response instead of masking defects.
@ExceptionHandler in Spring MVC — Handling Specific Exceptions
Direct Answer
@ExceptionHandler maps one or more exception types to a handler method in a controller or applicable @ControllerAdvice. Local handlers are useful for controller-specific behavior; advice is useful for a shared API contract. Neither placement is always superior. The most specific applicable exception mapping is preferred according to Spring's resolver rules.
Code Example
// LOCAL SCOPE - only handles exceptions from OrderController
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@GetMapping("/{id}")
public Order getOrder(@PathVariable Long id) {
throw new OrderNotFoundException("Order " + id + " not found");
}
@ExceptionHandler(OrderNotFoundException.class) // Only for this controller
public ResponseEntity<String> handleNotFound(OrderNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
}
}
// GLOBAL SCOPE - handles exceptions from ALL controllers
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(OrderNotFoundException.class) // Applies everywhere
public ResponseEntity<ErrorResponse> handleOrderNotFound(OrderNotFoundException ex, HttpServletRequest request) {
var error = new ErrorResponse(404, ex.getMessage(), LocalDateTime.now(), request.getRequestURI());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
record ErrorResponse(int status, String message, LocalDateTime timestamp, String path) {}
Common Mistakes & Pitfalls
- Thinking local handlers are global: Freshers often put @ExceptionHandler inside a @RestController expecting it to handle exceptions from all controllers — it only works for that one controller, leading to missed exceptions.
- Not returning proper HTTP status codes: Returning ResponseEntity.ok() from an exception handler defeats the purpose — clients need proper error status codes like 404, 400, or 500 to handle errors correctly.
- Handling too broadly: Writing @ExceptionHandler(Exception.class) in a local controller catches all exceptions from that controller, hiding bugs that should propagate to global handlers.
- Ignoring exception hierarchy: If you have @ExceptionHandler for both RuntimeException and IllegalArgumentException, Spring chooses the most specific match, but freshers often don't realize the order matters when exceptions inherit from each other.
Check your understanding
Answer these without looking back at the article.
- What is the difference between local and global @ExceptionHandler?
- Can you handle multiple exception types in one @ExceptionHandler method?
- How does Spring prioritize which @ExceptionHandler to use?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.