LiveLoveApp logo

CatchError Operator

catchError() Operator

To start with, you can almost think of the catchError() operator as similar to the built-in try...catch operator in JavaScript.

The catchError() Operator catches an error notification along with the original Observable that emitted the error notification, and returns a new Observable.

The catchError() operator can be useful performing a side effect when an error notification is emitted. You can also use the catchError() operator for retrying the source Observable that produced the error notification, however, be warned that this can result in the creation of Observables that recursively, and endlessly, emit error notifications.

Finally, the catchError() will catch error notifications that occur as a result of cold Observable producing an error or any operator that accepts a function from producing an error. The catchError() operator will not catch uncaught errors that occur during the production of values in a hot Observable, or during the subscription of a consumer to an Observable.

Example

Let's look at an example:

import { defer, Subject, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

const subject = new Subject<number>();

defer(() => {
  console.log('defer');
  return subject;
})
  .pipe(
    tap((value) => {
      if (value > 1) {
        throw new Error('Error emitted by throw');
      }
    }),
    catchError((error, caught) => {
      console.error('catchError', error);
      return throwError(error);
    })
  )
  .subscribe({
    error: (e) => console.error('observer', e),
    next: (value) => console.log('next', value),
    complete: () => console.log('complete')
  });

subject.next(1);
subject.next(2);

See example on codesandbox

In the code example above we are using the catchError() operator to catch the error notification produced by the tap() operator as a result of the throw JavaScript operator when the value is greater than 1.

Here is the expected result of the code above:

  1. First, the defer() operator logs the message "defer" to the console upon the first subscription.
  2. Next, the Subject, which is a hot Observable, emits a value of 1.
  3. The next function is invoked in the Observer with the value of 1 that is logged to the console. So far, all is good, no errors have been emited by the source Observable.
  4. Then, the Subject emits a value of 2.
  5. In this instance the tap() operator checks the value and uses the JavaScript throw operator to throw an exception. Internally, the tap() operator wraps the function invocation in a try...catch, and when an error occurs, returns a new Observable that immediately emits an error notification.
  6. The catchError subscribes to the incoming Observable and listens for the error notification, and only the error notification. When the error notification is emitted by the source Observable, the catchError() operator invokes the provided selector function. The selector function receives as arguments the error notification value and the source, or caught, Observable that emitted the error notification. Within the catchError() operator we first log the error to the console and then return a new Observable that is created by the throwError() operator, specifying the error value.

What do you think are the messages that we will see in the console?

There should be four messages in our console:

  1. defer
  2. next 1
  3. catchError Error
  4. observer: Error