Exceptions and exception filters
In NestJS you do not send an error by hand through the response object — you throw it as an exception. The built-in handler catches it and builds the JSON with the status code. An exception filter lets you replace that handler with your own when you need a different error format.
Built-in exceptions
Right now a request for a missing post returns an empty response with code 200. The correct answer is 404. Throw an exception in the service:
// src/posts/posts.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { Post } from './entities/post.entity';
@Injectable()
export class PostsService {
private posts: Post[] = [];
findOne(id: number): Post {
const post = this.posts.find((item) => item.id === id);
if (!post) {
throw new NotFoundException(`Post ${id} not found`);
}
return post;
}
}Open /posts/999 — you get a 404 response:
{
"message": "Post 999 not found",
"error": "Not Found",
"statusCode": 404
}The method now always returns Post rather than Post | undefined — the controller does not need to check the result.
| Exception | Code |
|---|---|
BadRequestException | 400 |
UnauthorizedException | 401 |
ForbiddenException | 403 |
NotFoundException | 404 |
ConflictException | 409 |
InternalServerErrorException | 500 |
All of them extend the HttpException class. For a rare code use it directly: throw new HttpException('Too many requests', 429).
An exception filter
A filter is a class that catches exceptions and sends the response itself. Let every blog error include the request address and the time:
nest g filter common/filters/http-exception --flat// src/common/filters/http-exception.filter.ts
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const http = host.switchToHttp();
const request = http.getRequest<Request>();
const response = http.getResponse<Response>();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
message: exception.message,
path: request.url,
timestamp: new Date().toISOString(),
});
}
}@Catch(HttpException) says which exceptions the filter catches. host.switchToHttp() gives access to the plain Express request and response objects.
Applying the filter
For the whole application — in src/main.ts:
// src/main.ts
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
app.useGlobalFilters(new HttpExceptionFilter());For one controller or method — with the @UseFilters(HttpExceptionFilter) decorator. Open /posts/999 again: the response now has a path field with /posts/999 and a timestamp.
Common mistake
If you throw a plain error, throw new Error('Post not found'), NestJS does not know its status code and answers 500 with Internal server error. The client cannot tell that the post simply does not exist. For expected situations always throw HttpException subclasses, and leave 500 for real failures.