Rxjs Observer filter not working for error

1.4k views Asked by At

I have the following code in my service

        let b = new BehaviorSubject({ a: undefined })
        let o = b.asObservable();
        o.pipe(filter(_ => _.a === 5)).subscribe(() => {
            debugger;
        }, error => {
            debugger
        })
        b.next({ a: 10 })
        b.next({ a: 5 })
        b.error({ a: 10 })

When I invoke b.next({a:10}) it does not hit the debugger in the onNext callback When I invoke b.next({a:5}) it hits the debugger in the onNext callback. When I invoke b.error({a:10}) it hits the debugger in the onError callback.

My expectation was the onError callback should not be called since the filter condition was not satisfied. But, clearly I have something wrong here.

How do I filter the errors too?

Thank you in advance.

2

There are 2 answers

1
Mrk Sef On BEST ANSWER

You can't filter errors for the same reason you can't filter completes. It doesn't make sense. They signal the end of a stream. You can't filter the end.

You can, of course, catch an error and then do nothing - which feels a bit like filtering an error.

o.pipe(
  catchError(err => 
    err?.a === 5 ?
    return of(err) :
    EMPTY
  ),
  filter(val => val.a === 5)
).subscribe({
  next: val => debugger,
  error: err => debugger,
  complete: () => debugger
});

Of course, anything you send to the subject after you error or complete will do nothing.

    b.next({ a: 10 }); // Filtered, not emitted
    b.next({ a: 5 }); // value emitted
    b.error({ a: 5 }); // caught and new non-error { a: 5 } emitted as value. subject 'b' is done
    b.next({ a: 5 }); // Does nothing

That final call will do nothing as the subject has errored/completed.

Similarily:

    b.next({ a: 10 }); // Filtered, not emitted
    b.next({ a: 5 }); // value emitted
    b.complete(); // subject 'b' is done
    b.next({ a: 5 }); // Does nothing

Finally:

    b.next({ a: 10 }); // Filtered, not emitted
    b.next({ a: 5 }); // value emitted
    b.error({ a: 10 }); // caught and not emitted. subject 'b' is done
    b.next({ a: 5 }); // Does nothing
0
Christoph142 On

I disagree with the "It doesn't make sense" assessment in the accepted answer. I found this question because I tried filtering in an interceptor that handles authentication errors (and only those) globally on all requests, but leaves actual application errors (status codes other than 401) to their respective error handlers. For anyone looking at similar problems: instead of filtering, do

return throwError(() => err);

for the latter unhandled cases in your interceptor to forward it to the next error handler in the chain.