Environment-Based Error Handling With Spring Boot and Kotlin

Simplifying debugging in the staging environment

Antonello Zanini
Sep 23 · 3 min read
Laptop featuring a 404 message sitting on a table.
Laptop featuring a 404 message sitting on a table.
Photo by Erik Mclean on Unsplash.

Providing simple but meaningful messages while handling errors in web services should be the preferred approach. This way, we will not expose any internal information about the causes of the errors and we will help the API client properly respond to issues.

When an error occurs, the default Spring Boot behavior is to return a stack trace. The main downside of this approach is that it might leak useful information about our implementation to a potential attacker. On the other hand, stack traces — unlike meaningful messages — are extremely important for debugging.

“Stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. Unfortunately, the same information can be useful to an attacker. The sequence of class names in a stack trace can reveal the structure of the application as well as any internal components it relies on.” — Semmle

The main goal of the approach we are going to present is to automatically adapt error messages according to the current deployment environment. In the staging environment, a simple and meaningful message, as well as a stack trace, will be returned. In the production environment, we will expose only the first one.

Let’s see how this can be achieved in Spring Boot and Kotlin.

Handling Different Deployment Environments

To understand which deployment environment we are in, we will use a custom environment variable called ENV. We assume that its value is PRODUCTION in the production environment and STAGING in the staging environment. In Kotlin, environment variables value can be retrieved as follows:

System.getenv("env_name")

Defining a Custom Error Class

We are going to define a custom class called ErrorMessage to represent API errors. The goal of this class is to wrap exceptions in a nice JSON representation to make life easier for API clients.

We can implement such a class as follows:

As you can notice, the stackTrace attribute is nullable and optional since it will be used in the staging environment only.

Spring Boot Environment-Based Error Handling

Using @ExceptionHandler and @ControllerAdvice is one of the main methods to handle errors since Spring Boot 3.2.

@ExceptionHandler is a Spring annotation that provides a mechanism to treat exceptions that are thrown during execution of handlers (Controller operations). This annotation, if used on methods of controller classes, will serve as the entry point for handling exceptions thrown within this controller only. Altogether, the most common way is to use @ExceptionHandler on methods of @ControllerAdvice classes so that the exception handling will be applied globally or to a subset of controllers.” — Toptal

Thanks to them, we can build a global error handling component called ControllerExceptionHandler. Its goal is to catch exceptions and wrap them in ErrorMessage objects, which will be serialized into JSON and sent back to API clients. It also implements the environment-based logic, as shown below:

The most important method is generateResponse, which converts the exception stack trace to a String (as described in this course) and passes it to the ErrorResponse constructor only when not in the production environment.

Example of the same error response in the production and staging environment, respectively.

This way, the message attribute can be used to explain what happened to users. In the staging environment, developers can understand why the error occurred thanks to the stackTrace attribute.

Extra

This tutorial can be used to build a custom error-handling layer to add to the multi-layered architecture we presented in this article.

Conclusion

Not being able to understand why an error occurred can be frustrating! Exposing detailed error descriptions can be dangerous. There is a way to cautiously face this issue, however. Using the approach above, when an error occurs, users will always see a simple message. But when in the staging environment, developers will have everything they need to debug it.

That’s all, folks! I hope this helps you handle errors in Spring Boot and Kotlin. Let me know if you have any comments or suggestions.

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store