RFC 7807 ProblemDetail in Spring Boot 3
Fast recall
Quick revision
Core answer
application/problem+json — a small fixed shape (type, title, status, detail, instance) with free-form extension members for context. Spring Framework 6 / Boot 3 ship this as the `ProblemDetail` class plus the `ErrorResponse` interface; ResponseEntityExceptionHandler auto-produces it for the built-in Spring MVC exceptions, and you plug in domain translations via @RestControllerAdvice with @ExceptionHandler methods that return ProblemDetail (or throw an ErrorResponseException). Set spring.mvc.problemdetails.enabled=true (Boot 3.0+) to make Spring emit ProblemDetail for framework exceptions too. The envelope is the same across validation, auth, domain, and unexpected errors — that uniformity is the whole point.Whether you know RFC 7807 is the IETF standard error envelope, can use Spring 6's `ProblemDetail` and `ErrorResponse` API, wire one `@RestControllerAdvice` to cover domain + framework + fallback, and add extension members (`code`, `traceId`, `errors[]`) without breaking the contract.
Mixing ProblemDetail responses for some endpoints and Spring Boot's legacy `{timestamp, status, error, message, path}` for others — because `spring.mvc.problemdetails.enabled=false` (the Boot 3 default) leaves framework exceptions on the old shape. Also: using `ProblemDetail.forStatus(...)` without ever setting `type`, so every problem has the default `about:blank` URI and no way to branch on problem class.
Explain the `ErrorResponse` vs `ErrorResponseException` split, `MessageSource` internationalisation of the `title`/`detail`, extending `DefaultHandlerExceptionResolver`, and how Spring 6 auto-maps common MVC exceptions (`MethodArgumentNotValidException`, `HttpMessageNotReadableException`, `MaxUploadSizeExceededException`) into typed ProblemDetail responses when problemdetails is enabled.
Interview-ready guide
Interview answer
RFC 7807 is the IETF standard for HTTP error bodies, and Spring 6 turned it into first-class plumbing.
The envelope
- Five standard fields:
type,title,status,detail,instance - Plus free-form extension members — where
code,traceId, and field-levelerrors[]go - Content-Type is
application/problem+json
Spring 6 primitives
ProblemDetail— mutable bean with setters for each field andsetPropertyfor extensionsErrorResponse— interface any exception can implement to be auto-mappedErrorResponseException— ready-made RuntimeException; throw it and Spring serialises itResponseEntityExceptionHandler— base class your advice extends to override built-ins
The one-line fix most projects miss
spring.mvc.problemdetails.enabled=true— without it, framework exceptions (bad JSON, validation, missing resource) return the legacy{timestamp, status, error, path}shape while your custom advice emits ProblemDetail — mixed envelopes on the same API
Fields I always set
typeURI pointing at docs — never leave it asabout:blank- Short
title— same for every occurrence of this problem class detail— specific to this occurrence, for developer tools not end usersinstance— request path, set automatically by Spring if null
Extensions I add by convention
code— stable SCREAMING_SNAKE_CASE enum clients branch ontraceId— correlation with APM and logserrors[]for validation —{field, code, message}per field- Domain context — balance, required, resource IDs
Single advice covers everything
ErrorResponsehandler stampstraceIdandinstanceMethodArgumentNotValidExceptionoverride emits field-level errorsHttpMessageNotReadableExceptionoverride for bad JSON bodiesAuthenticationExceptionfor 401 withWWW-Authenticate- Final
Throwablecatch-all — logs the stack trace, returnsINTERNAL_ERRORwithtraceId
Common mistakes
- Leaving
spring.mvc.problemdetails.enabled=false— mixed envelopes - Never setting
type— every response hasabout:blank - Echoing
ex.getMessage()indetail— leaks ORM/SQL internals - Rebuilding ProblemDetail from scratch in every controller — DRY violation, drift
- Reusing
codes across unrelated problems — clients false-match
Testing
- MockMvc or WebTestClient assertions on status,
Content-Type: application/problem+json,code, and extension members - The envelope is public contract; tests prevent silent regressions
RFC 7807 ProblemDetail in Spring Boot 3
Direct Answer
RFC 7807 defines application/problem+json — a small fixed shape (type, title, status, detail, instance) with free-form extension members for context. Spring Framework 6 / Boot 3 ship this as the ProblemDetail class plus the ErrorResponse interface; ResponseEntityExceptionHandler auto-produces it for the built-in Spring MVC exceptions, and you plug in domain translations via @RestControllerAdvice with @ExceptionHandler methods that return ProblemDetail (or throw an ErrorResponseException). Set spring.mvc.problemdetails.enabled=true (Boot 3.0+) to make Spring emit ProblemDetail for framework exceptions too. The envelope is the same across validation, auth, domain, and unexpected errors — that uniformity is the whole point.
Code Example
# application.yml
spring:
mvc:
problemdetails:
enabled: true # framework exceptions -> application/problem+json
webflux:
problemdetails:
enabled: true # same flag for WebFlux
messages:
basename: messages # for i18n of titles / details
# Without the flag, Spring Boot still returns ProblemDetail for exceptions
# your own @ExceptionHandler methods produce, but framework exceptions
# (e.g. bad JSON body) fall back to the legacy error shape.
# A sample response with the flag enabled:
# HTTP/1.1 404 Not Found
# Content-Type: application/problem+json
#
# {
# "type": "https://errors.api.acme.com/resource/not-found",
# "title": "Resource not found",
# "status": 404,
# "detail": "Order ord_abc123 was not found.",
# "instance": "/v1/orders/ord_abc123",
# "code": "ORDER_NOT_FOUND",
# "traceId": "7a9c3f12b4e84e0a"
# }
Common Mistakes & Pitfalls
Mixing ProblemDetail responses for some endpoints and Spring Boot's legacy {timestamp, status, error, message, path} for others — because spring.mvc.problemdetails.enabled=false (the Boot 3 default) leaves framework exceptions on the old shape. Also: using ProblemDetail.forStatus(...) without ever setting type, so every problem has the default about:blank URI and no way to branch on problem class.
Check your understanding
Answer these without looking back at the article.
- What does the `spring.mvc.problemdetails.enabled` flag actually change, and why is it false by default?
- Why prefer implementing `ErrorResponse` on a domain exception over building the ProblemDetail in an advice?
- How do you add field-level errors to a ProblemDetail response for `MethodArgumentNotValidException`?
- When would you use `MessageSource` to localize the `title` and `detail` of a ProblemDetail?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.