Exceptions are an incredibly important part of any real-world application. Proper exception handling is often the difference between a professionally built and an amateurish application.

As a result, exception handling is one of the most important fundamentals in NestJS.

In this post, I will cover the in-built NestJS Exception Handling.

1 – NestJS Global Exception Handler

NestJS comes pre-packaged with an in-built exceptions layer.

This layer is responsible for processing all unhandled exceptions.

In a way, this layer acts as a safety net.

In other words, if the code you write does not handle a particular exception, the exceptions layer will handle it. It will also send an appropriate response.

Internally, there is a global exception filter that takes care of the actual exception handling. This global exception filter handles all exceptions of type HttpException as well as any subclasses that inherit from HttpException.

When a particular exception is unrecognized, the built-in exception filter generates a default JSON response. Here, unrecognized means an exception that does not inherit from the standard HttpException directly or indirectly.

{
  "statusCode": 500,
  "message": "Internal server error"
}

As you can see, this is not a very user-friendly response message.

An Internal Server Error could mean a dozen things and it will be tough for the consumer to figure out what went wrong. Moreover, you would often want to throw specific exceptions in case of specific situations.

NestJS exception handling provides support for the same.

2 – Throwing Standard Exceptions in NestJS

As discussed, NestJS has an in-built HttpException class as part of the @nestjs/common package.

Here’s an example demonstrating how to throw an exception from our NestJS application.

import { Controller, Get, HttpException, HttpStatus } from "@nestjs/common";
import { ProductsService } from "./products.service";

@Controller('products')
export class ProductsController {

    constructor(private readonly productsService: ProductsService) {}

    @Get('admin')
    getAdminDetails() {
        throw new HttpException('Forbidden endpoint', HttpStatus.FORBIDDEN);
    }
}

The getAdminDetails() is the route handler for the admin route. Within the function getAdminDetails(), you throw an HttpException.

You can learn more about controllers and route handlers with my detailed post on NestJS Controllers.

When you call the endpoint http://localhost:3000/products/admin, you get the below response.

{
  "statusCode": 403,
  "message": "Forbidden"
}

The response body consists of the statusCode value and the message value that you provided in the constructor of the HttpException class.

As you may have guess, the HttpException constructor takes two required arguments as input:

  • response – This defines the JSON response body and can contain a string or object value. In our example, we hard-code the response body to the string value ‘Forbidden endpoint’.
  • status – This argument defines the HTTP Status Code. In the code example, you set the status code to 403 using the enum HttpStatus.FORBIDDEN.

Both the HttpException class and HttpStatus enum are provided by the @nestjs/common package.

3 – Custom Response Body for a NestJS Exception

The JSON response body consists of two parts:

  • The status code that defaults to the status code provided in the constructor.
  • Second one is the message part that provides a brief description of the exception.

You can override this standard response by providing your own response object in the response argument.

Nest will automatically serialize the object and return it as the response.

Also, the constructor of the HttpException class takes a third optional argument as well. This argument is known as options and you can use it to provide an error cause.

The cause object is not serialized into the response object, but it can be used for logging purposes.

See the below example:

import { Controller, Get, HttpException, HttpStatus } from "@nestjs/common";
import { ProductsService } from "./products.service";

@Controller('products')
export class ProductsController {

    constructor(private readonly productsService: ProductsService) {}

    @Get('admin')
    getAdminDetails() {
        try {
            this.productsService.getAllProducts()
        } catch (err) {
            throw new HttpException({
                status: HttpStatus.FORBIDDEN,
                error: 'You are forbidden to access the endpoint',
              }, HttpStatus.FORBIDDEN, {
                cause: err
              });
        }
    }
}

Notice that you are passing an object instead of a string in the response attribute of the HttpException constructor. Also, you are adding the optional property cause and assigning it the value of the err object generated by the try-catch block.

If you access the endpoints now, you will get the below response in case of an error.

{
  "status": 403,
  "error": "You are forbidden to access the endpoint"
}

4 – How to customize the NestJS Exception?

You don’t need to write custom exceptions frequently because the built-in Nest HTTP exception is quite sufficient for most requirements.

However, you may need to create customized exceptions sometimes for some specialized requirements. In such cases, it’s still a good practice to use the existing exception hierarchy.

In other words, any custom exceptions you create should inherit from the base HttpException class. This allows NestJS to recognize your custom exceptions and handle the error responses automatically.

Check the below example:

export class ForbiddenException extends HttpException {
  constructor() {
    super('You are forbidden to access the endpoint', HttpStatus.FORBIDDEN);
  }
}

The ForbiddenException class extends the base HttpException class.

Now, you can directly use this exception class in your application code.

@Controller('products')
export class ProductsController {

    constructor(private readonly productsService: ProductsService) {}

    @Get('admin')
    getAdminDetails() {
        throw new ForbiddenException();
    }
}

What’s Next?

Here’s a summary of what you have learnt in this post.

  • Understanding the global exception filter
  • How to throw standard exceptions?
  • How to customize the exception for better control?

The in-built exception handling in NestJS is extremely robust and can serve a wide variety of requirements.

However, sometimes you may still need to customize the entire exception-handling flow.

In the follow-up post, I will cover the important concept of NestJS Exception Filters that will help you get even greater control over exceptions in NestJS.

If you have any comments or queries, please feel free to write in the comments section below.


NestJS is a fundamental pillar in my Cloud & Backend learning path. To know more, don’t forget to subscribe to the Progressive Coder newsletter.

Also, say ‘Hi’ on Twitter for more real-time updates on what’s happening at Progressive Coder.

Categories: BlogNestJS

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *