From harness-claude
Implements NestJS global exception filters with @Catch and ExceptionFilter for consistent error responses, mapping Prisma/TypeORM errors to HTTP exceptions, and logging with request context.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Handle errors globally with @Catch, ExceptionFilter, and custom exception hierarchies
Provides error handling patterns, exception filters, error boundaries, logging, retries, and recovery strategies for React, Next.js, and NestJS apps. Use for async errors, monitoring integration, and graceful degradation.
Enforces NestJS best practices for modular architecture, dependency injection scoping, exception filters, class-validator DTO validation, and Drizzle ORM integration. Use when designing modules, providers, filters, DTOs, or ORM in NestJS apps.
Provides expert Nest.js guidance on enterprise Node.js architecture, dependency injection, decorators, middleware, guards, interceptors, pipes, testing strategies, database integration, and authentication. Validates with typecheck, unit, integration, e2e tests.
Share bugs, ideas, or general feedback.
Handle errors globally with @Catch, ExceptionFilter, and custom exception hierarchies
{ error, message, statusCode, timestamp })export class ResourceNotFoundException extends HttpException {
constructor(resource: string, id: string) {
super({ error: 'NOT_FOUND', message: `${resource} ${id} not found` }, HttpStatus.NOT_FOUND);
}
}
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
constructor(private readonly logger: Logger) {}
catch(exception: unknown, host: ArgumentsHost): void {
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';
this.logger.error(exception, { url: request.url, method: request.method });
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter { ... }
@Catch(PrismaClientKnownRequestError)
export class PrismaExceptionFilter implements ExceptionFilter {
catch(exception: PrismaClientKnownRequestError, host: ArgumentsHost) {
if (exception.code === 'P2002') {
// unique constraint violation
}
if (exception.code === 'P2025') {
// record not found
}
}
}
providers: [{ provide: APP_FILTER, useClass: AllExceptionsFilter }];
Or without DI: app.useGlobalFilters(new AllExceptionsFilter()).
Exception filters are the final layer of the NestJS request pipeline. They catch exceptions that were not caught by interceptors or handlers and convert them to HTTP responses.
@Catch() with no arguments catches ALL exceptions including non-HTTP ones (uncaught database errors, third-party SDK failures). This is useful as a safety net but should log the error and return a generic 500.
@Catch(HttpException) specifically only intercepts NestJS HTTP exceptions, leaving non-HTTP exceptions to bubble up to the next filter (or the runtime).
Prisma error codes:
P2002 — Unique constraint violation → ConflictExceptionP2025 — Record not found → NotFoundExceptionP2003 — Foreign key constraint failure → BadRequestExceptionException hierarchy design: Build a DomainException extends HttpException base, then specific exceptions like InsufficientInventoryException extends DomainException. The filter only needs to handle DomainException and extract the structured payload.
WebSocket and microservice contexts: ArgumentsHost is transport-agnostic. Use host.getType() to check whether the request is HTTP, WS, or RPC before calling switchToHttp().
https://docs.nestjs.com/exception-filters