Skip to main content

Error Filter

Error filters allow you to catch and process errors that occur during request handling. They provide a centralized way to transform application errors into appropriate HTTP responses, keeping your controllers clean and focused on business logic.

Error filter and injectable decorators

You don't need to add @injectable(). The @CatchError() decorator already applies it for you.

How Error Filters Work

Error filters are classes that implement the ErrorFilter interface and are decorated with @CatchError(). When an error occurs during request processing, Inversify HTTP looks for error filters that can handle that specific error type and delegates the error handling to them.

The error filter can then:

  • Transform the error into an appropriate HTTP response
  • Log the error for debugging purposes
  • Add context or sanitize error messages
  • Return custom error responses based on the error type

Basic Example

Here's a complete example showing how to create a custom error, an error filter to handle it, and a controller that uses the error filter:

Custom Error

First, create a custom error class:

export class InvalidOperationError extends Error {
constructor(message: string = 'Invalid operation', options?: ErrorOptions) {
super(`[InvalidOperationError]: ${message}`, options);
}
}

Error Filter

Create an error filter that catches the custom error and returns an appropriate HTTP response:

@CatchError(InvalidOperationError)
export class InvalidOperationErrorFilter implements ErrorFilter<InvalidOperationError> {
public catch(error: InvalidOperationError): void {
throw new UnprocessableEntityHttpResponse(
{ message: error.message },
error.message,
{
cause: error,
},
);
}
}
universal error filter and infinite loops

When creating a universal error filter (one that catches anything), be cautious about throwing HttpResponse errors from within the filter. This can lead to infinite loops if the filter catches its own thrown errors. Instead, consider returning the response directly.

Controller

Apply the error filter to a controller using the @UseErrorFilter() decorator:

@Controller('/products')
@UseErrorFilter(InvalidOperationErrorFilter)
export class ProductController {
@Get('/:id/validate')
public async validateProduct(): Promise<void> {
throw new InvalidOperationError('Product validation failed');
}
}

Returning responses from error filters

Error filters can directly manipulate the HTTP response using the adapter-specific request and response objects. This approach is particularly useful for global error filters that need to handle all types of errors without causing infinite loops.

Examples by Adapter

@CatchError()
export class GlobalErrorFilter implements ExpressErrorFilter {
readonly #logger: Logger;

constructor() {
this.#logger = new ConsoleLogger('GlobalErrorFilter');
}

public catch(
err: unknown,
_request: express.Request,
response: express.Response,
): void {
if (isHttpResponse(err)) {
this.#logger.http(
`HttpResponse error: ${JSON.stringify(err, Object.getOwnPropertyNames(err))}`,
);

response.status(err.statusCode).send(err.body);

return;
}

this.#logger.error(
`Unhandled error: ${JSON.stringify(err, Object.getOwnPropertyNames(err))}`,
);

const internalServerErrorStatusCode: number = 500;

response.status(internalServerErrorStatusCode).send({
error: 'Internal Server Error',
message: 'Unhandled error',
statusCode: internalServerErrorStatusCode,
});
}
}

In these examples:

  • The error filter implements the adapter-specific ErrorFilter type (e.g., ExpressErrorFilter, FastifyErrorFilter)
  • A logger is instantiated using ConsoleLogger from @inversifyjs/logger to log errors
  • The isHttpResponse() utility checks if the caught error is an HttpResponse instance
  • If it's an HttpResponse, the filter logs it with .http() level and sends the response with the original status code and body
  • For generic errors, the filter logs them with .error() level using JSON.stringify(err, Object.getOwnPropertyNames(err)) to properly serialize the error (see why this is necessary)
  • The filter returns a 500 Internal Server Error response for generic errors
  • The filter is registered globally using adapter.useGlobalFilters(GlobalErrorFilter)

This pattern ensures that:

  • HttpResponse errors (like NotFoundHttpResponse, InternalServerErrorHttpResponse) are handled without infinite loops
  • Generic JavaScript errors are caught, logged, and transformed into proper HTTP responses
  • Error details are properly serialized for logging (Error objects have non-enumerable properties that require special handling)
  • Error handling and logging are centralized and consistent across your application

Attaching error filters

Use the UseErrorFilter decorator at the controller level (applies to all routes) or at the method level (applies to one route).

Global error filters can be registered using the InversifyHttpAdapter.