Spring Boot Error Response Design
Fast recall
Quick revision
Core answer
@RestControllerAdvice. Use focused @ExceptionHandler methods, return the correct HTTP status with a safe ProblemDetail, keep private diagnostics in server logs, and test every path that can produce an error.Interview-ready guide
Interview answer
A consistent error response means that the same kind of failure has the same HTTP status and the same common JSON fields across the API. In Spring MVC, @RestControllerAdvice is a shared place for this translation. A service can throw a meaningful exception such as OrderNotFoundException, and one focused @ExceptionHandler can turn it into the public response. Controllers no longer need their own copies of error-building code.
Choose the status from what failed. A missing order maps to 404 Not Found; an update blocked by the order's current state can map to 409 Conflict; and an unknown bug becomes a safe 500 Internal Server Error. In Spring Boot 3.3, spring.mvc.problemdetails.enabled=true enables Problem Details support for built-in Spring MVC exceptions. Custom domain failures still need deliberate handlers. Authentication and access failures can occur before MVC, so Spring Security's entry point and access-denied handler must follow the same public contract.
Spring's ProblemDetail represents the standard RFC 9457 problem fields. type identifies a stable kind of problem, title is a short summary, status matches the HTTP response, detail safely explains this occurrence, and instance can identify this request or path. An extension such as code: ORDER_NOT_FOUND or a list of field errors is useful only when its name and shape stay documented.
The client response and the server log serve different readers. The response should contain enough information to recover, but it should not expose stack traces, SQL messages, secrets, internal host names, or Java package names. Store those diagnostics in protected logs with a request or correlation ID. A catch-all handler is a final safety net, not a replacement for clear handlers for expected failures.
Tests should call the real web layer and verify the full contract: status, application/problem+json, required fields, extension fields, and important headers. Cover malformed JSON, invalid input, a missing resource, a state conflict, authentication, access denial, and one unexpected exception. Add an assertion that private exception text never appears in the response.
Spring Boot Error Response Design
Direct Answer
Create one public error contract, then map failures to it in a shared @RestControllerAdvice. Use focused @ExceptionHandler methods, return the correct HTTP status with a safe ProblemDetail, keep private diagnostics in server logs, and test every path that can produce an error.
Deep Dive & Architecture
An API error is part of the public contract. The HTTP status gives general HTTP software the outcome. The problem body gives this application's stable problem type and safe details. Returning 200 OK with an error flag breaks that agreement because gateways, monitoring, clients, and caches still see a successful HTTP response.
Spring MVC offers several exception boundaries. A focused @ExceptionHandler can handle one expected domain failure, and @RestControllerAdvice shares handlers across controllers. For built-in MVC exceptions, Spring Boot 3.3 enables framework Problem Details support when spring.mvc.problemdetails.enabled=true; extending ResponseEntityExceptionHandler is useful when the application needs to customize those responses. A local controller handler has narrower scope, and Spring Security handles failures raised before a controller. The design is consistent only when each path has an owner and all owners produce the same common fields.
ProblemDetail is a container for the standard RFC 9457 fields and optional extension properties. The type should stay stable for the kind of problem; detail can change for the current occurrence. Spring uses the status value as the HTTP status, prefers a problem media type during content negotiation, and can use the current request path as instance when the application did not set one.
Known application failures should have deliberate mappings. A missing order becomes 404, a state conflict becomes 409, and invalid input normally becomes the API's documented 400 or 422 response. Security failures must keep required authentication headers. Unknown failures become a generic 500 response, while the actual exception stays in protected logs.
The last step is contract testing. Calling the real MVC or integration layer checks serialization, status, media type, headers, and exception resolution together. A direct unit test of the handler method cannot prove all of those behaviors.
Code Example
Focused handler inside @RestControllerAdvice
@ExceptionHandler(OrderNotFoundException.class)
ProblemDetail handleNotFound(OrderNotFoundException ex) {
ProblemDetail problem = ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND,
"No order exists with id " + ex.orderId());
problem.setType(URI.create(
"https://api.example.com/problems/order-not-found"));
problem.setTitle("Order not found");
problem.setProperty("code", "ORDER_NOT_FOUND");
return problem;
}
The lesson shows only the mapping logic. The complete checked fixture supplies the advice class, imports, exception, controller, and test setup.
Focused web-layer assertion
mockMvc.perform(get("/orders/42"))
.andExpect(status().isNotFound())
.andExpect(content().contentTypeCompatibleWith(
MediaType.APPLICATION_PROBLEM_JSON))
.andExpect(jsonPath("$.status").value(404))
.andExpect(jsonPath("$.code").value("ORDER_NOT_FOUND"))
.andExpect(jsonPath("$.detail")
.value("No order exists with id 42"));
This request verifies Spring's exception resolution, HTTP status, problem media type, and serialized public fields together. Spring can fill instance from the request path when the handler does not set it.
Check your understanding
Answer these without looking back at the article.
- What is the difference between ProblemDetail type and instance?
- Why should a catch-all handler return a generic detail?
- When would an API deliberately map validation to 422 instead of Spring's common 400 response?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.