# 3. What the defaults do not do: record validation failures with no error body [Prev: Record validation](02-record-validation.md) | [README](../README.md) Source: [`ContactController.java`](../src/main/java/com/ankurm/customvalidation/web/ContactController.java). Test: [`ValidationScenariosTest.java`](../src/test/java/com/ankurm/customvalidation/ValidationScenariosTest.java), [`ProblemDetailsEnabledTest.java`](../src/test/java/com/ankurm/customvalidation/ProblemDetailsEnabledTest.java). Transcripts: [`docs/output/03-record-based-spam-rejected.txt`](output/03-record-based-spam-rejected.txt), [`docs/output/03b-record-based-spam-rejected-accept-json.txt`](output/03b-record-based-spam-rejected-accept-json.txt), [`docs/output/07-problemdetails-enabled-record-rejected.txt`](output/07-problemdetails-enabled-record-rejected.txt). ## The surprise this chapter exists to document `ContactController#submitContactForm` (the class-based endpoint) declares a `BindingResult` parameter immediately after `@Valid ContactForm`. That is what lets it inspect `bindingResult.getFieldErrors()` and hand back a `{"message": "..."}` body of its own construction. A record parameter has nowhere convenient to put an equivalent `BindingResult` in this codebase's controller signatures, so `submitContactFormRecord` has none -- and a failing constraint on the record path throws `MethodArgumentNotValidException` instead of populating a result object. The assumption going in was that Spring's default handling of that exception would still produce *some* readable body. It does not, by default: ``` $ curl -s -i -X POST localhost:8080/contact-record \ -H 'Content-Type: application/json' \ -d '{"email":"spammy@email.com","message":"This is spam."}' HTTP status: 400 Body: '' (empty!) ``` ([`docs/output/03-record-based-spam-rejected.txt`](output/03-record-based-spam-rejected.txt))
An Accept: application/json header does not change this. It was tested directly rather than assumed -- see docs/output/03b-record-based-spam-rejected-accept-json.txt. The empty body is not a content-negotiation problem; nothing is being negotiated because nothing is being written.
## The property that changes this, and what it still does not give you `spring.mvc.problemdetails.enabled=true` (a property that already existed in Spring Boot 3, not new in 4.1) turns on RFC 9457 `ProblemDetail` responses for framework-thrown MVC exceptions, `MethodArgumentNotValidException` included: ``` HTTP status: 400 Content-Type: application/problem+json Body: {"detail":"Invalid request content.","instance":"/contact-record","status":400,"title":"Bad Request"} ``` ([`docs/output/07-problemdetails-enabled-record-rejected.txt`](output/07-problemdetails-enabled-record-rejected.txt)) Progress -- there is now a body, and a real HTTP status-coded RFC 9457 document -- but read it closely: no mention of "spam", no field name, no constraint message. Boot's default mapping fills in only the generic fields (`title`, `status`, a fixed `detail` string). The per-field detail the class-based endpoint hand-rolls from `bindingResult.getFieldErrors()` is not reproduced automatically; getting it back needs a custom `@ExceptionHandler` (or a `ResponseEntityExceptionHandler` override of `handleMethodArgumentNotValid`) that reads the exception's `BindingResult` -- the exception itself still carries one, even though the controller signature does not expose it -- and writes the field errors into the `ProblemDetail`'s own `properties` map.
Turning on spring.mvc.problemdetails.enabled is not, by itself, a drop-in replacement for the BindingResult-based error reporting pattern most Spring tutorials (including the earlier version of this one) teach. It replaces an empty body with a standardised envelope; it does not replace the work of putting your validation messages inside that envelope.
## Going deeper - [Spring Framework `ProblemDetail` reference](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-ann-rest-exceptions.html) (rel="nofollow") - [RFC 9457: Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457) (rel="nofollow") - See also this repo's [`problem-details/`](../problem-details) module, built for a different ankurm.com article specifically about `ProblemDetail` and global exception handling in depth. - Prev: [Record validation](02-record-validation.md)