What are exception filters in NestJS?
Exception Filters in NestJS
Exception Filters handle all unhandled exceptions across the application. They catch exceptions and format the HTTP response. NestJS has a built-in global exception filter, but you can create custom filters for fine-grained control.
Built-in HTTP Exceptions
NestJS provides a set of standard exceptions out of the box:
typescript
import {
BadRequestException, // 400
UnauthorizedException, // 401
ForbiddenException, // 403
NotFoundException, // 404
ConflictException, // 409
UnprocessableEntityException, // 422
InternalServerErrorException, // 500
BadGatewayException, // 502
} from '@nestjs/common';
throw new NotFoundException('User not found');
throw new BadRequestException('Invalid email format');
throw new ConflictException('Email already registered');
throw new UnauthorizedException();HttpException Base Class
typescript
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
// With custom response object
throw new HttpException(
{ status: 403, error: 'Forbidden', hint: 'Contact admin' },
HttpStatus.FORBIDDEN
);Custom Exception
typescript
export class BusinessRuleException extends HttpException {
constructor(message: string, rule: string) {
super({ message, rule, statusCode: 422 }, HttpStatus.UNPROCESSABLE_ENTITY);
}
}
throw new BusinessRuleException('Cannot delete account with active orders', 'ACTIVE_ORDERS');Custom Exception Filter
typescript
import {
ExceptionFilter, Catch, ArgumentsHost,
HttpException, HttpStatus, Logger
} from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
private readonly logger = new Logger(HttpExceptionFilter.name);
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const request = ctx.getRequest<Request>();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const exceptionResponse = exception.getResponse();
const error = typeof exceptionResponse === 'string'
? { message: exceptionResponse }
: exceptionResponse as object;
this.logger.error(`${request.method} ${request.url} — ${status}`);
response.status(status).json({
...error,
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}Catch-All Filter
typescript
@Catch() // no argument = catch everything
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message = exception instanceof HttpException
? exception.getResponse()
: 'Internal server error';
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}Applying Filters
typescript
// Method-level
@Post()
@UseFilters(HttpExceptionFilter)
create(@Body() dto: CreateUserDto) { ... }
// Controller-level
@Controller('users')
@UseFilters(HttpExceptionFilter)
export class UsersController {}
// Global — main.ts
app.useGlobalFilters(new HttpExceptionFilter());
// Global — module (supports DI, preferred)
@Module({
providers: [
{ provide: APP_FILTER, useClass: AllExceptionsFilter },
],
})Summary
Exception filters centralize error formatting. Use the built-in HttpException subclasses for most cases. Create a global @Catch() filter to catch everything, log errors, and return consistent JSON error responses. Register globally via APP_FILTER to benefit from dependency injection.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.