Rxjava: UnknownHostException is not handled by stream

Created on 19 Jun 2017  Â·  9Comments  Â·  Source: ReactiveX/RxJava

I'm using RxJava 2 and Retrofit 2 to processing my REST calls. After migration from RxJava 1.x to RxJava 2.x I started getting a lot of unhandled java.net.UnknownHostException exceptions. I was expecting to get onError callback in case of any error during REST call. But seems like not. After deep investigation I found that error handling works a bit different in RxJava 2 (based on this).

Does anybody know if UnknownHostException is not processed by stream and doesn't call onError of the stream? Should UnknownHostException be handled in a way using RxJavaPlugins.setErrorHandler()?

RxJava: 2.1.0
RxAndroid: 2.0.1
Retrofit: 2.2.0
OkHttp: 3.6.0

2.x Android Question Retrofit

Most helpful comment

As to why, the wiki has more information:
https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling
As to where, typically somewhere at the beginning of the program, before any RxJava calls have been made.

All 9 comments

It depends on what is throwing it. Normally, if there are no other errors around, you should see it via regular onError. The stacktrace should give us a hint.

Are they wrapped with UndeliverableException?

On Mon, Jun 19, 2017, 16:02 David Karnok notifications@github.com wrote:

It depends on what is throwing it. Normally, if there are no other errors
around, you should see it via regular onError. The stacktrace should give
us a hint.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/ReactiveX/RxJava/issues/5425#issuecomment-309432675,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA7B3J4sVuR-IaNZrHZuDJDbWB64j1-Mks5sFnFtgaJpZM4N-MTo
.

Here is stacktrace

Fatal Exception: io.reactivex.b.f: java.net.UnknownHostException: Unable to resolve host "example.com": No address associated with hostname
       at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:349)
       at io.reactivex.internal.operators.observable.ObservableUnsubscribeOn$UnsubscribeObserver.onError(ObservableUnsubscribeOn.java:67)
       at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onError(ObservableSubscribeOn.java:63)
       at io.reactivex.internal.operators.observable.ObservableOnErrorNext$OnErrorNextObserver.onError(ObservableOnErrorNext.java:78)
       at io.reactivex.internal.disposables.EmptyDisposable.error(EmptyDisposable.java:63)
       at io.reactivex.internal.operators.observable.ObservableError.subscribeActual(ObservableError.java:37)
       at io.reactivex.Observable.subscribe(Observable.java:10842)
       at io.reactivex.internal.operators.observable.ObservableOnErrorNext$OnErrorNextObserver.onError(ObservableOnErrorNext.java:105)
       at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.checkTerminate(ObservableFlatMap.java:495)
       at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drainLoop(ObservableFlatMap.java:331)
       at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drain(ObservableFlatMap.java:323)
       at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onError(ObservableFlatMap.java:288)
       at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onError(BodyObservable.java:72)
       at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:55)
       at io.reactivex.Observable.subscribe(Observable.java:10842)
       at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
       at io.reactivex.Observable.subscribe(Observable.java:10842)
       at io.reactivex.internal.operators.observable.ObservableFlatMap.subscribeActual(ObservableFlatMap.java:55)
       at io.reactivex.Observable.subscribe(Observable.java:10842)
       at io.reactivex.internal.operators.observable.ObservableOnErrorNext.subscribeActual(ObservableOnErrorNext.java:38)
       at io.reactivex.Observable.subscribe(Observable.java:10842)
       at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
       at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:452)
       at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
       at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

Looks like the flow has been disposed just when the error propagates downwards. How does the code look like and what triggers the dispose if any?

Here is the code, but I'm not sure if it's helpful

Observable<UserData> userSettings = refreshUserSettings();
Observable<UserData> userData = refreshUserData();

mSubscription = new SerialSubscription()

mSubscription.set(Observable.concat(userSettings, userData)
                                                  .subscribeOn(Schedulers.io())
                                                  .observeOn(AndroidSchedulers.mainThread())
                                                  .subscribe(new SyncSubscriber())));
...
@Override
protected void onDestroy() {
        mSubscription.unsubscribe();
        super.onDestroy();
}

How does SyncSubscriber works?
Is it possible for you to show refreshUserSettings() and refreshUserData()?

Ok, so after deep debugging session and investigation the source code of RxJava, I discovered that an exception was wrapped with UndeliverableException (even though it's not in stacktrace). So adding RxJavaPlugins.setErrorHandler() solves the problem and handles UnknownHostException wrapped with UndeliverableException. Also, it was nice discovery that first the callback onError of my subscriber is called and only after that I was reaching global error handler. What means exactly that an exception was propagated when the stream was already closed.

Thanks everybody for support! Issue is resolved.

@dkhmelenko Where should i add RxJavaPlugins.setErrorHandler() ?
and Why should i add RxJavaPlugins.setErrorHandler() ?

As to why, the wiki has more information:
https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling
As to where, typically somewhere at the beginning of the program, before any RxJava calls have been made.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

philleonard picture philleonard  Â·  3Comments

yubaokang picture yubaokang  Â·  3Comments

dzharikhin picture dzharikhin  Â·  4Comments

ZakTaccardi picture ZakTaccardi  Â·  3Comments

Jaap-van-Hengstum picture Jaap-van-Hengstum  Â·  3Comments