Error handling with Spring WebFlux

Posted at — Apr 11, 2022
Riekpil logo
Learn how to test real-world applications with the Testing Spring Boot Applications Masterclass. Comprehensive online course with 8 modules and 130+ video lessons to master well-known Java testing libraries: JUnit 5, Mockito, Testcontainers, WireMock, Awaitility, Selenium, LocalStack, Selenide, and Spring's Outstanding Test Support.

My error-handling-spring-boot-starter library had its first release almost 2 years ago. The first reported issue came soon after with a request to support Spring WebFlux. As I don’t have any Spring WebFlux projects myself, it was pretty low on my priority list. Especially as it did not seem trivial to add support.

Luckily, about a month ago Fabio Marini opened a PR with all the building blocks I needed to add support for Spring WebFlux to the library.

Version 3.0.0 has now been released which can be used with Spring WebFlux.

Had to do a small bugfix for the @WebFluxTest support so the current version is now 3.0.1 (I should have done the release blog entry before the release :-) )

To get started, create a Spring Boot application at and select 'Spring Reactive Web' from the dependencies list. Optionally, also select 'Validation' if you want to use the validation annotations.

Add the error-handling-spring-boot-starter library in the pom.xml:

<project xmlns="" xmlns:xsi=""

Now we can build a simple rest controller:

public class MyRestController {

    private final UserService service;

    public MyRestController(UserService service) {
        this.service = service;

    Mono<UserDto> findUser(@PathVariable("id") Long id) {
        return service.findUserById(id)
                      .map(user -> new UserDto(;

With UserService:

import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

public class UserService {

    private final Map<Long, User> users = new HashMap<>();

    public UserService() {
        users.put(1L, new User("Wim"));
        users.put(2L, new User("Simon"));
        users.put(3L, new User("Siva"));
        users.put(4L, new User("Josh"));

    public Mono<User> findUserById(Long userId) {
        User user = users.get(userId);
        if (user == null) {
            throw new UserNotFoundException(userId);
        return Mono.just(user);

User and UserDto are just 2 simple records:

public record User(String name) {

public record UserDto(String name) {


Now run the application and try the endpoint with your favorite HTTP client (Mine is the one from IntelliJ IDEA):

GET localhost:8080/users/1


  "name": "Wim"

If we use an id that does not exist:

GET localhost:8080/users/10

Then we get this error response:

  "code": "USER_NOT_FOUND",
  "message": "No user found for id 10",
  "userId": 10

The userId property is added in the JSON resonse because we used the @ResponseErrorProperty annotation in the exception class:

import io.github.wimdeblauwe.errorhandlingspringbootstarter.ResponseErrorProperty;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

public class UserNotFoundException extends RuntimeException {
    private final Long userId;

    public UserNotFoundException(Long userId) {
        super("No user found for id " + userId);
        this.userId = userId;

    public Long getUserId() {
        return userId;

We can also validate this with the following @WebFluxTest test:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.reactive.server.WebTestClient;

class MyRestControllerTest {

    WebTestClient webTestClient;

    void testUserNotFound() {
                     .jsonPath("$.message").isEqualTo("No user found for id 10")



The error-handling-spring-boot-starter library is fully ready for Spring WebFlux.

See reactive-error-handling on GitHub for the full sources of this example.

If you have any questions or remarks, feel free to post a comment at GitHub discussions.

If you want to be notified in the future about new articles, as well as other interesting things I'm working on, join my mailing list!
I send emails quite infrequently, and will never share your email address with anyone else.