Exception message not included in response when throwing ResponseStatusException in Spring Boot
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When you throw a ResponseStatusException with a reason message in Spring Boot 2.3+, the message does not appear in the JSON error response by default. This is because Spring Boot changed the default behavior to hide error details for security reasons — exposing internal error messages to clients can leak implementation details. To include the message, you must set server.error.include-message=always in application.properties, or use a custom error handler.
The Problem
Expected response:
Actual response (Spring Boot 2.3+):
The message field is empty even though you passed "User not found with id: 42" to the exception.
Fix 1: Configure application.properties
Or in YAML:
The options for include-message are:
never(default in Spring Boot 2.3+) — always emptyalways— always includedon_param— included only when the request has amessageparameter
After this change, the reason from ResponseStatusException appears in the response:
Fix 2: Custom Exception Handler with @ControllerAdvice
For full control over the error response format, use @ControllerAdvice:
This bypasses Spring Boot's default error handling entirely and lets you include or exclude any field.
Fix 3: Custom Error Attributes
Override DefaultErrorAttributes to customize what Spring Boot's default error response includes:
Fix 4: Custom Exception Classes
Instead of ResponseStatusException, define specific exception classes for cleaner error handling:
Other Hidden Error Properties
Spring Boot 2.3+ also hides stack traces and binding errors by default:
For production, keep the defaults (never) and use @ControllerAdvice to return only safe, user-facing messages.
Spring Boot Version History
| Version | Default include-message | Behavior |
| Spring Boot 2.0-2.2 | Messages included by default | Reason appears in response |
| Spring Boot 2.3+ | never | Messages hidden by default |
| Spring Boot 3.x | never | Same as 2.3+, uses Jakarta namespace |
The change was introduced in Spring Boot 2.3 (May 2020) as a security improvement to prevent accidental information leakage.
Common Pitfalls
- Not knowing the default changed in Spring Boot 2.3: Code that worked in Spring Boot 2.2 silently stops showing error messages after upgrading. Add
server.error.include-message=alwaysif you relied on the old behavior. - Exposing internal details in production: Setting
include-message=alwaysin production can leak database column names, query details, or internal paths. Use@ControllerAdviceto sanitize messages for production andinclude-message=alwaysonly in development profiles. - Confusing
reasonwithmessage:ResponseStatusExceptionusesgetReason(), notgetMessage(). ThegetMessage()method returns the HTTP status description combined with the reason, whilegetReason()returns just your custom message. - Using
@ResponseStatuson the exception class AND throwingResponseStatusException: If you annotate a custom exception with@ResponseStatusand also wrap it inResponseStatusException, the status codes may conflict. Use one approach consistently. - Forgetting to handle exceptions in reactive WebFlux: In WebFlux,
ResponseStatusExceptionworks differently — it returns the message by default. Theserver.error.include-messageproperty only applies to the servlet (MVC) stack.
Summary
- Spring Boot 2.3+ hides
ResponseStatusExceptionreason messages by default for security - Set
server.error.include-message=alwaysinapplication.propertiesfor the quickest fix - Use
@RestControllerAdvicewith@ExceptionHandlerfor full control over error responses - Define custom exception classes instead of
ResponseStatusExceptionfor cleaner, more maintainable error handling - Keep error messages hidden in production and use structured error responses to avoid leaking internal details

