Handling HTTP Errors and Custom Error Pages in Micronaut

When building web applications or REST APIs, things can go wrong:

  • Client sends invalid data.
  • Requested resource is not found.
  • Server encounters an unexpected error.

Handling errors gracefully is extremely important.

Micronaut provides simple yet powerful ways to:

  • Handle HTTP errors.
  • Customize error responses.
  • Create user-friendly error pages.

In this post, you’ll learn HTTP Errors and Custom Error Pages in Micronaut step-by-step with simple examples.

Handling HTTP Errors and Custom Error Pages in Micronaut

Why Proper Error Handling Matters

  • Better User Experience: Users get clear messages instead of cryptic errors.
  • Consistent API responses: Clients (mobile apps, frontends, etc.) know what to expect.
  • Easier Debugging: Well-structured error info helps you fix issues faster.
  • Security: Avoid exposing sensitive details accidentally.

Types of Errors

TypeExample
Client Errors (4xx)400 Bad Request, 404 Not Found
Server Errors (5xx)500 Internal Server Error
Custom Business ErrorsValidation failed, Resource already exists

Micronaut allows you to handle all of these easily.

Default Error Handling in Micronaut

Micronaut automatically handles many HTTP errors.
For example:

  • If you access a non-existing route → 404 Not Found
  • If a request body is invalid → 400 Bad Request

By default, Micronaut returns a JSON response like:


{
  "message": "Page Not Found"
}

But usually, you want custom error responses that fit your app.

Scenario Example: School Management System

We are building a simple REST API for schools.
If a student with a given ID is not found, we want to return a custom error message.

Step 1: Create a Micronaut Project


mn create-app com.kscodes.micronaut.errorhandling --build=maven --lang=java

Step 2: Create a Student Class


package com.kscodes.micronaut.errorhandling;

public class Student {
    private Long id;
    private String name;
    private String grade;

    public Student() {
    }

    public Student(Long id, String name, String grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }

    // Getters and setters omitted for brevity
}

Step 3: Create a Custom Exception

We’ll throw this exception when a student is not found.


package com.kscodes.micronaut.errorhandling;

public class StudentNotFoundException extends RuntimeException {
    public StudentNotFoundException(Long id) {
        super("Student with id " + id + " not found");
    }
}

Step 4: Create a Controller


package com.kscodes.micronaut.errorhandling;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/students")
public class StudentController {

    @Get("/{id}")
    public Student getStudent(Long id) {
        if (id == 1) {
            return new Student(1L, "John Doe", "5th");
        } else {
            throw new StudentNotFoundException(id);
        }
    }
}

✅ If student is not found, we throw our custom exception.

Step 5: Handle the Exception Globally

Now let’s create a global exception handler.


package com.kscodes.micronaut.errorhandling;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Produces;
import io.micronaut.http.server.exceptions.ExceptionHandler;
import jakarta.inject.Singleton;
@Produces
@Singleton
public class StudentNotFoundExceptionHandler implements ExceptionHandler> {
    @Override
    public HttpResponse handle(HttpRequest request, StudentNotFoundException exception) {
        ErrorResponse error = new ErrorResponse(404, exception.getMessage());
        return HttpResponse.notFound(error);
    }
}

✅ Explanation:

  • We implement ExceptionHandler.
  • Return a custom JSON error response.

Step 6: Create ErrorResponse Class

This class defines the structure of our custom error message.


package com.kscodes.micronaut.errorhandling;

public class ErrorResponse {
    private int status;
    private String message;

    public ErrorResponse() {
    }

    public ErrorResponse(int status, String message) {
        this.status = status;
        this.message = message;
    }

    // Getters and setters omitted for brevity
}

Step 7: Test the Error Handling

Run your app:

mvn mn:run

Success case:

http://localhost:8080/students/1


{
  "id": 1,
  "name": "John Doe",
  "grade": "5th"
}


Error case:

http://localhost:8080/students/2


{
  "status": 404,
  "message": "Student with id 2 not found"
}

🎯 Custom error handling works perfectly!

Bonus: Handle All Other Exceptions Globally

You can even create a global fallback handler:


package com.kscodes.micronaut.errorhandling;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Produces;
import io.micronaut.http.server.exceptions.ExceptionHandler;
import jakarta.inject.Singleton;
@Produces
@Singleton
public class GlobalExceptionHandler implements ExceptionHandler> {
    @Override
    public HttpResponse handle(HttpRequest request, Exception exception) {
        ErrorResponse error = new ErrorResponse(500, "Internal Server Error");
        return HttpResponse.serverError(error);
    }
}

Optional: Custom Error Pages (For Web Apps)

For web applications (not APIs), you can also define custom HTML error pages.

Example:

  • Create a file:
    src/main/resources/views/errors/404.html




    Page Not Found


    

Oops! Page Not Found.

✅ Micronaut will automatically serve this page on 404 errors for browser clients.

Summary Table

FeatureMicronaut
Global Exception HandlingExceptionHandler interface
Custom JSON ErrorCreate response DTO
Handle 404, 500, etc.Fully supported
Custom Error PagesServe HTML files under /views/errors

Conclusion

  • ✅ HTTP Errors and Custom Error Pages in Micronaut are easy to handle
  • ✅ Use ExceptionHandler to catch and handle exceptions globally.
  • ✅ Customize both API responses and web error pages.
  • ✅ Your users and API clients will love your clean error messages!

Further Reading

  1. Micronaut Exception Handling Official Docs
    👉 https://docs.micronaut.io/latest/guide/#exceptionHandler
  2. Micronaut Views and Error Pages
    👉 https://docs.micronaut.io/latest/guide/#views