Skip to content

Actual exception is being hidden by OnErrorFailedException #3679

Closed
@ktchernov

Description

@ktchernov

Using RxJava 1.10 (and similar issue on 1.0.15), I stumbled upon a mysterious stack trace that made no sense in my app, after a lot of debugging, I found that RxJava will report the wrong exception in some scenarios. For example, if you run this sample code:

Observable.just(1).doOnNext(new Action1<Integer>() {
        @Override public void call(Integer val) {
            throw new IllegalStateException("doOnNextException");
        }
    }).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
        @Override public Observable<?> call(Observable<? extends Throwable> errorObservable) {
            return errorObservable.flatMap(new Func1<Throwable, Observable<?>>() {
                @Override public Observable<?> call(Throwable throwable) {
                    return Observable.just(3).delay(1, TimeUnit.SECONDS).doOnNext(
                            new Action1<Integer>() {
                                @Override public void call(Integer integer) {
                                    throw new UnsupportedOperationException("retry exception");
                                }
                            });
                }
            });
        }
    }).subscribe(new Subscriber<Integer>() {
        @Override public void onCompleted() {
            Log.v("EX", "onCompleted");
        }

        @Override public void onError(Throwable e) {
            Log.v("EX", "onError");
            throw new IllegalThreadStateException();
        }

        @Override public void onNext(Integer integer) {
            Log.v("EX", "onNext");
        }
    });

The expected behaviour should be that IllegalThreadStateException (thrown within the onError handler of the subscriber) is included as the cause. However, the actual stack trace contains UnsupportedOperationException as the cause - which is not the problem in the code snippet above. the UnsupportedOperationException is totally fine, but the problem arises when onError throws.

This leads to a stack trace that points to the wrong cause and does not include the actual cause (which would be the IllegalThreadStateException). If I removed the retryWhen() block - then the stack trace correctly includes IllegalThreadStateException as the exception from within onError.

The (incorrect) trace from the code snippet above:

Process: com.example.mydemoapp, PID: 14118
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:818)
 Caused by: rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError
    at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:194)
    at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:120)
    at rx.internal.operators.OnSubscribeRedo$4$1.onError(OnSubscribeRedo.java:331)
    at rx.internal.operators.OperatorMerge$MergeSubscriber.reportError(OperatorMerge.java:240)
    at rx.internal.operators.OperatorMerge$MergeSubscriber.checkTerminate(OperatorMerge.java:776)
    at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:537)
    at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:526)
    at rx.internal.operators.OperatorMerge$InnerSubscriber.onError(OperatorMerge.java:810)
    at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:71)
    at rx.exceptions.Exceptions.throwOrReport(Exceptions.java:187)
    at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:82)
    at rx.internal.operators.OperatorDelay$1$3.call(OperatorDelay.java:88)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:818) 
 Caused by: rx.exceptions.CompositeException: 2 exceptions occurred. 
    at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:194) 
    at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:120) 
    at rx.internal.operators.OnSubscribeRedo$4$1.onError(OnSubscribeRedo.java:331) 
    at rx.internal.operators.OperatorMerge$MergeSubscriber.reportError(OperatorMerge.java:240) 
    at rx.internal.operators.OperatorMerge$MergeSubscriber.checkTerminate(OperatorMerge.java:776) 
    at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:537) 
    at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:526) 
    at rx.internal.operators.OperatorMerge$InnerSubscriber.onError(OperatorMerge.java:810) 
    at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:71) 
    at rx.exceptions.Exceptions.throwOrReport(Exceptions.java:187) 
    at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:82) 
    at rx.internal.operators.OperatorDelay$1$3.call(OperatorDelay.java:88) 
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:818) 
 Caused by: rx.exceptions.CompositeException$CompositeExceptionCausalChain: Chain of Causes for CompositeException In Order Received =>
    at android.util.Log.getStackTraceString(Log.java:504)
    at com.android.internal.os.RuntimeInit.Clog_e(RuntimeInit.java:59)
    at com.android.internal.os.RuntimeInit.access$200(RuntimeInit.java:43)
    at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:91)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:66)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:818) 
 Caused by: java.lang.UnsupportedOperationException: retry exception
    at com.example.mydemoapp.MainActivity$3$1$1.call(MainActivity.java:74)
    at com.example.mydemoapp.MainActivity$3$1$1.call(MainActivity.java:72)
    at rx.Observable$11.onNext(Observable.java:4445)
    at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:80)
    at rx.internal.operators.OperatorDelay$1$3.call(OperatorDelay.java:88)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:818) 
 Caused by: rx.exceptions.OnErrorThrowable$OnNextValue: OnError while emitting onNext value: 3
    at rx.exceptions.Exceptions.throwOrReport(Exceptions.java:187)
    at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:82)
    at rx.internal.operators.OperatorDelay$1$3.call(OperatorDelay.java:88) 
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:818) 

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions