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.

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
Type | Example |
---|---|
Client Errors (4xx) | 400 Bad Request, 404 Not Found |
Server Errors (5xx) | 500 Internal Server Error |
Custom Business Errors | Validation 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:
1 2 3 4 5 6 |
{ "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
1 2 3 4 |
mn create-app com.kscodes.micronaut.errorhandling --build=maven --lang=java |
Step 2: Create a Student Class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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.
1 2 3 4 5 6 7 8 9 10 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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<StudentNotFoundException, HttpResponse<ErrorResponse>> { @Override public HttpResponse<ErrorResponse> 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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
1 2 3 4 5 6 7 8 9 |
{ "id": 1, "name": "John Doe", "grade": "5th" } |
Error case:
http://localhost:8080/students/2
1 2 3 4 5 6 7 |
{ "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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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<Exception, HttpResponse<ErrorResponse>> { @Override public HttpResponse<ErrorResponse> 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
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html> <head> <title>Page Not Found</title> </head> <body> <h1>Oops! Page Not Found.</h1> </body> </html> |
✅ Micronaut will automatically serve this page on 404 errors for browser clients.
Summary Table
Feature | Micronaut |
---|---|
Global Exception Handling | ExceptionHandler interface |
Custom JSON Error | Create response DTO |
Handle 404, 500, etc. | Fully supported |
Custom Error Pages | Serve 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
- Micronaut Exception Handling Official Docs
👉 https://docs.micronaut.io/latest/guide/#exceptionHandler - Micronaut Views and Error Pages
👉 https://docs.micronaut.io/latest/guide/#views