Global error handling fails to catch re-thrown HTTP errors in rxjs throwError scenario

Purpose: Implementing a global error handler for server errors and application errors generated in Typescript code.

Approach: Utilizing a custom ErrorHandler from a library project within the same workspace. The library structure is as follows:

https://i.sstatic.net/xAaKF.png

Below is the HTTP interceptor (http-error.interceptor.ts)

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {

  constructor(@Inject(LOGGER_SERVICE) private logger: ILoggerService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req)
    .pipe(
        catchError( (error: HttpErrorResponse) => {
          console.log('error');

          return throwError(error);
        })
    );
  }
}

Here's the custom global error handler (errors-handler.ts):

import { ErrorHandler, Injectable } from '@angular/core';

@Injectable()
export class ErrorsHandler implements ErrorHandler {

    handleError(error: any): void {
        console.log('hi!');
    }

}

Additionally, the error-handling.module.ts:

import { NgModule, ErrorHandler } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptor } from './http-error.interceptor';
import { ErrorsHandler } from './errors-handler';

    @NgModule({
      declarations: [],
      imports: [
      ],
      exports: [],
      providers: [
        {provide: ErrorHandler, useClass: ErrorsHandler},
        {provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true}
      ]
    })
    export class ErrorHandlingModule { }

The public_api.ts file solely exports the module

/*
 * Public API Surface of error-handling
 */

export * from './lib/error-handling.module';

In the same workspace, an app (Angular CLI's default app, located outside the projects folder) is present. The ErrorHandlingModule is imported in app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { ErrorHandlingModule } from '@common/error-handling';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { CoreModule } from './core/core.module';



@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    CoreModule,

    ErrorHandlingModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

The @common/error-handling library has been successfully built. A fake API using json-server defines a "categories" endpoint. This service is called in app.component.ts within the onInit method, resulting in a 404 HTTP error response due to calling the "categorie" endpoint (without "s"). The console output upon serving the app includes:

https://i.sstatic.net/n0VyD.png

While the 404 error and "error" log from http-error.interceptor.ts are visible, the "hi!" log from the custom ErrorHandler is not. The global error handler functions correctly when an error is thrown from app.component.ts after calling the fake API endpoint. However, the line

return throwError(error);

in http-error.interceptor.ts does not reach the global error handler.

Could this issue be related to zone.js? The error seems to be caught there and not propagated to the rest of the application. My understanding of zone.js is limited.

Any other insights?

Thank you in advance!

Regards, Max.

Answer №1

export class CustomErrorHandlingModule { 
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: CustomErrorHandlingModule,
      providers: [
        {provide: ErrorHandler, useClass: CustomErrorsHandler},
        {provide: HTTP_INTERCEPTORS, useClass: CustomHttpErrorInterceptor, multi: true} ]
    };
}

and later in the MainAppModule, import using

CustomErrorHandlingModule.forRoot()

For additional reference - https://angular.io/api/router/RouterModule#forRoot

Answer №2

When your observable uses a callback for errors, the throwError operator will bypass the global error interceptor and be sent directly to the observer.

To prevent this, simply disable or comment out the catchError block in the subscribe function.

getWorkData(id: string): void {
this.userDataService.getWorkData(id).subscribe(
  (response) => {
    this.Id = response.Id;
    this.localStorage.setItem('WorkData', response);
  }
  // (err) => {
  //   //this.monitoringService.logException(err);
  // },
);
}

Answer №3

Shoutout to @avramz for the insightful answer. Here's a more detailed breakdown of my approach:

Snippet of Bootstrap code

providers: [...,
  {
    provide: HTTP_INTERCEPTORS,
    useClass: HttpErrorInterceptorService,
    multi: true,
  },
]

Snippet of Service code

@Injectable({ providedIn: 'root' })
export class HttpErrorInterceptorService implements HttpInterceptor {

  constructor(
    readonly matSnackbar: MatSnackBar,
  ) {
  }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError(e => {
        this.matSnackbar.showErrorUnexpected(`Something unexpected happened (${e.status})`);
        return throwError(() => e);
      }),
    );
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Create a definition file containing a class that can be easily extended

I am attempting to define an interface in a declaration file: declare namespace Foo{ export interface Bar{ new(attrs, options) } } Then I want to inherit from this interface in my code: class Chunk extends Foo.Bar {} However, I encounte ...

Most effective methods for validating API data

Currently, I am working on developing an api using nestjs. However, I am facing some confusion when it comes to data validation due to the plethora of options available. For instance, should I validate data at the route level using schema validation (like ...

How to implement SVG in React with the image source as a parameter?

I've been working on a React component in NextJS that displays an image inside a hexagon. The issue I'm facing is that when I try to use multiple instances of this component with different images in the HexagonWall, all hexagons end up displaying ...

Implementing Node.js microservices with AWS Cognito leveraging Amplify's best practices

I am currently working on developing a Node.js API that is broken down into several small APIs (microservices) communicating with each other through requests and responses. Additionally, I am utilizing Angular for the frontend. My next step is to enhance ...

Has anyone discovered an Angular2 equivalent to $provide.value() while testing promises?

I am currently experimenting with testing a promise in Angular2. Here is what I have so far: this.fooService.getData().then(data => this.fooData = data); If you are interested in learning about testing promises for Angular 1, check out this article. ...

Tips for customizing the background color in the angular2-tree component

As a newcomer to Angular 4, I have been attempting to incorporate angular2-tree into my project. However, I am struggling to figure out how to dynamically set the background color of each node. I have been trying to include a "color" attribute in our dat ...

Having difficulty sending emails with attachments using AngularJS

While using Angular, I encountered an issue when sending an email with an attachment. The response I received contained the data code of the file instead of its actual format. See example: https://i.stack.imgur.com/vk7X8.png I am unsure what is causing t ...

Angular request: HTTP request<any> is not generic

Struggling with creating an error interceptor service in Angular. Having trouble instantiating a HttpRequest. New to Angular and Web App development. Here is my code snippet: import { Injectable } from '@angular/core'; import { HttpInterceptor ...

"I am facing issues with Nodejs $lookup as it is not producing the

I am looking to merge two document collections. The first collection, "prefix," contains an array of category IDs under the categoryId key, while the second collection, "categories," holds objects with a unique _id field. Here is my sample database structu ...

Unexpected error in boot.ts file in Angular 2

I am currently experimenting with various folder arrangements for Angular 2. When attempting to launch a local server, I encounter the following error: Uncaught SyntaxError: Unexpected token < Evaluating http://localhost:3000/prod/app/TypeScript/bo ...

What is the best way to compress a file for transfer to a server using gzip?

While attempting to upload a file and send it to the server via a REST API, I am looking for a reliable method to gzip the file. Unfortunately, there is limited documentation available on this topic. Can anyone suggest the most effective approach to achiev ...

Is there an alternative method to incorporate the 'environment.ts' file into a JSON file?

In my Angular application, I need to import assets based on the env configuration. I am attempting to extract the patch information from environment.ts and save it into my assets as a json file. However, I am unsure of the proper method to accomplish this. ...

Angular positions the <style> element following the custom stylesheet <link>

I need help understanding Angular styling. Currently, I am working with Angular 10 and Prime-ng. I have created a custom style to override a Prime-ng component's style. However, when I serve the app for testing, the custom style does not override it ...

Setting up CORS for Azure Active Directory

My goal is to programmatically obtain an access token from Azure Active Directory in an Angular 6 application using the method below. let body1 = new FormData() body1.append("resource", environment.config.clientId) body1.append("grant_type", " ...

Error: Uncaught TypeError - Unable to access 'reduce' property of undefined value

Currently, I am focusing on implementing yup validation. Specifically for FileList validation, encountering an issue where leaving the input empty triggers the following error message: enter image description here Below is the code snippet in question: (C ...

The real-time updates on an Angular 2 website can be seen across multiple devices simultaneously

Just getting started with Angular 2 and ran into an interesting issue. When setting up my website, NPM defaults the server to http://localhost:3000. To test the site on another computer, I tried accessing it using my IP address http://10.x.x.x:3000 and eve ...

Using TypeScript along with the "this" parameter

Hi there, I'm encountering an issue with the code snippet below. It keeps throwing an error message that says "Property 'weatherData' does not exist on type 'XMLHttpRequest'." The purpose of this code is to display weather informat ...

Trouble with maps not showing up and the console isn't showing any errors when using @react-google-m

Currently, I am facing an issue while trying to integrate Google Maps by following a blog post that provides instructions on next13 TypeScript. Despite reaching the point where the maps should be displayed, nothing appears on the screen. Surprisingly, ther ...

Encountering an error message during the installation of 'ngx-toastr' within an Angular project

Whenever I attempt to install 'ngx-toastr', I encounter an error message. Additionally, my website is being created using Bootstrap. ERROR npm ERR! Could not resolve dependency: npm ERR! peer @angular/common@">=16.0.0-0" from <a ...

Refresh a Google chart without having to reload the entire page

I currently have a button that allows me to refresh the data on my page in case there is new data available through an API. Although this button successfully refreshes my datatable, it does not redraw the Google charts I have integrated into my project usi ...