What is the ErrorResponse / ErrorResponseException contract and how does it relate to ProblemDetail?
answer
- ErrorResponse = status + headers + body(ProblemDetail)
- ProblemDetail = body only
- ErrorResponseException = throwable ErrorResponse
- getDetailMessageCode / getTitleMessageCode → MessageSource i18n
- Spring's own web exceptions implement ErrorResponse
basics
~20 sErrorResponse is an interface representing a complete error response: HTTP status, headers, and a ProblemDetail body. ErrorResponseException is a ready-made RuntimeException implementing it. Spring's own web exceptions implement ErrorResponse so they render as problem+json automatically.
solid answer
~40 sorg.springframework.web.ErrorResponse is an abstraction over an entire HTTP error response — getStatusCode(), getHeaders(), and getBody() returning a ProblemDetail — decoupling exception classes from how the body is built. ProblemDetail models just the body; ErrorResponse models status + headers + body together. Spring's framework exceptions (ResponseStatusException, MethodArgumentNotValidException, etc.) implement ErrorResponse, which is why they render as RFC 7807 bodies. ErrorResponseException is a concrete RuntimeException implementing ErrorResponse that you can throw directly or subclass for your own exceptions. ErrorResponse also carries message codes — getDetailMessageCode() and getTitleMessageCode() — plus arguments, so a MessageSource can resolve localized detail/title text. Implementing ErrorResponse (vs a plain exception plus an @ExceptionHandler) is the idiomatic way for library/framework exceptions to be self-describing.
code
java · 20 linesimport org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.ErrorResponseException;
// Self-rendering, i18n-ready domain exception
public class OutOfCreditException extends ErrorResponseException {
public OutOfCreditException(long balance, long cost) {
super(HttpStatus.PAYMENT_REQUIRED,
ProblemDetail.forStatusAndDetail(
HttpStatus.PAYMENT_REQUIRED,
"Your balance " + balance + " is below the cost " + cost),
null);
setTitle("Out of credit");
getBody().setProperty("balance", balance);
}
// Detail message code defaults to:
// problemDetail.com.example.OutOfCreditException
// resolved via MessageSource for localization.
}go deeper
Awareness that ErrorResponseException is a throwable that produces a problem body is enough.
Distinguish ProblemDetail (body) from ErrorResponse (status+headers+body) and know ErrorResponseException.
Explain the message-code i18n mechanism and when to implement ErrorResponse vs write an @ExceptionHandler.
Discuss designing a library's exception hierarchy on ErrorResponse for self-describing, localizable, framework-agnostic errors.
## Two layers: body vs whole response - **`ProblemDetail`** (`org.springframework.http.ProblemDetail`) models only the *body* — the RFC 7807 fields. - **`ErrorResponse`** (`org.springframework.web.ErrorResponse`) models the *whole* error response: `getStatusCode()` (an `HttpStatusCode`), `getHeaders()` (an `HttpHeaders`), and `getBody()` (a `ProblemDetail`). It ties status + headers + body into one contract. This separation lets an exception advertise everything Spring needs to render it, without an external `@ExceptionHandler` translating it. ## Why it exists Before Spring 6, mapping an exception to an HTTP response usually meant writing an `@ExceptionHandler`. `ErrorResponse` lets the exception itself be the single source of truth. Any exception that implements `ErrorResponse` is rendered directly by Spring's default exception handling (and by `ResponseEntityExceptionHandler`). Spring converted its own web exceptions — `ResponseStatusException`, `MethodArgumentNotValidException`, `HttpMediaTypeNotSupportedException`, `MissingRequestHeaderException`, and many more — to implement `ErrorResponse`. That is the mechanism behind uniform RFC 7807 output for framework errors. ## ErrorResponseException `org.springframework.web.ErrorResponseException` is a concrete `RuntimeException implements ErrorResponse`. You can: - **Throw it directly**: `throw new ErrorResponseException(HttpStatus.CONFLICT, problemDetail, cause);` - **Subclass it** for a typed domain exception that is self-rendering. ```java public class OutOfCreditException extends ErrorResponseException { public OutOfCreditException(int balance) { super(HttpStatus.PAYMENT_REQUIRED, forStatusAndDetail(HttpStatus.PAYMENT_REQUIRED, "Insufficient credit"), null); getBody().setProperty("balance", balance); } } ``` ## Message resolution / i18n `ErrorResponse` also exposes **message codes** for internationalization: - `getDetailMessageCode()` — defaults to `problemDetail.<fully.qualified.ExceptionClassName>`. - `getTitleMessageCode()` — defaults to `problemDetail.title.<fully.qualified.ExceptionClassName>`. - `getDetailMessageArguments()` — arguments spliced into the localized message. At render time `ResponseEntityExceptionHandler` (or `ErrorResponse.updateAndGetBody(MessageSource, Locale)`) looks these codes up in a configured `MessageSource` and overwrites `detail`/`title` with the localized text. So you can put `problemDetail.com.example.OutOfCreditException=No tienes suficiente crédito` in `messages_es.properties`. The helper `ErrorResponse.builder(...)` also exists for assembling one fluently without a dedicated class. ## Contract vs handler — when to use which - **Implement `ErrorResponse`** (usually by extending `ErrorResponseException`) when the exception is thrown from many places or from library code and should be self-describing and i18n-ready. - **Write an `@ExceptionHandler`** when you are adapting a *third-party* or legacy exception you cannot modify, or when the mapping needs request context. ## Gotchas - `getBody()` returns a live `ProblemDetail`; mutate it in the constructor to add properties. - Message-code lookup only happens if a `MessageSource` is wired and the codes resolve; otherwise the literal `detail`/`title` you set are used. - `ErrorResponse` lives in `spring-web`, so it is shared by MVC and WebFlux.
- What is the difference between ProblemDetail and ErrorResponse?ProblemDetail models only the RFC 7807 response body; ErrorResponse models the whole error response — status code, headers, and the ProblemDetail body — plus message codes for i18n.
- What message code does ErrorResponse use by default to localize the detail text?problemDetail.<fully-qualified exception class name>, looked up in the configured MessageSource; the title uses problemDetail.title.<class name>.
- Why did Spring make its own exceptions implement ErrorResponse?So they are self-describing and render uniformly as RFC 7807 bodies without every app writing @ExceptionHandlers, and so their detail/title can be internationalized via message codes.
saying these in an interview costs you the question
- Saying ErrorResponse and ProblemDetail are the same thing
- Claiming ErrorResponseException requires an @ExceptionHandler to render (it renders via the ErrorResponse contract directly)
- Not knowing framework exceptions implement ErrorResponse and thinking you must map each one manually