Careeroza
Global Exception Filter
Catching Everything
A filter class has @Catch() (empty = every exception) and a catch(exception, host) method that writes the response.
src/common/filters/all-exceptions.filter.ts
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, Logger } from '@nestjs/common';
import type { Request, Response } from 'express';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = new Logger(AllExceptionsFilter.name);
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const req = ctx.getRequest<Request>();
const res = ctx.getResponse<Response>();
const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
const body = exception instanceof HttpException ? exception.getResponse() : 'Internal server error';
const message = typeof body === 'string' ? body : (body as { message?: unknown }).message;
if (status >= 500) this.logger.error(`${req.method} ${req.url}`, (exception as Error)?.stack);
res.status(status).json({
success: false,
error: { statusCode: status, message, path: req.url, requestId: req.headers['x-request-id'] ?? null },
timestamp: new Date().toISOString(),
});
}
}Registering It
Register it as an APP_FILTER provider (preferred, because the filter can inject services) or with app.useGlobalFilters(new AllExceptionsFilter()) in main.ts.
// app.module.ts
import { APP_FILTER } from '@nestjs/core';
@Module({
providers: [{ provide: APP_FILTER, useClass: AllExceptionsFilter }],
})
export class AppModule {}A filter for only one exception type uses @Catch(OutOfStockException). With several filters, the most specific binding (method, then controller, then global) is tried first.
Example
curl http://localhost:3000/products/999Example output
{"success":false,"error":{"statusCode":404,"message":"Product 999 not found","path":"/products/999","requestId":"9b2f0f8e"},"timestamp":"2026-01-15T10:00:00.000Z"}