Search code examples
androidrx-javarx-java2

onError complains about supplied value


I love RxJava, but I have to admit that sometimes it can be quite tough to debug.

I am getting an error

Fatal Exception: java.lang.NullPointerException: Value supplied was null
       at io.reactivex.internal.operators.single.SingleOnErrorReturn$OnErrorReturn.onError(SingleOnErrorReturn.java:66)
       at io.reactivex.internal.operators.single.SingleDelayWithCompletable$OtherObserver.onError(SingleDelayWithCompletable.java:64)
       at io.reactivex.internal.operators.completable.CompletableFromSingle$CompletableFromSingleObserver.onError(CompletableFromSingle.java:41)
       at io.reactivex.internal.operators.single.SingleOnErrorReturn$OnErrorReturn.onError(SingleOnErrorReturn.java:68)
       at io.reactivex.internal.observers.ResumeSingleObserver.onError(ResumeSingleObserver.java:51)
       at io.reactivex.internal.disposables.EmptyDisposable.error(EmptyDisposable.java:78)
       at io.reactivex.internal.operators.single.SingleError.subscribeActual(SingleError.java:42)
       at io.reactivex.Single.subscribe(Single.java:3666)
       at io.reactivex.internal.operators.single.SingleResumeNext$ResumeMainSingleObserver.onError(SingleResumeNext.java:80)
       at io.reactivex.internal.operators.single.SingleMap$MapSingleObserver.onError(SingleMap.java:69)
       at io.reactivex.internal.operators.single.SingleMap$MapSingleObserver.onError(SingleMap.java:69)
       at io.reactivex.internal.operators.observable.ObservableToListSingle$ToListObserver.onError(ObservableToListSingle.java:104)
       at io.reactivex.observers.SerializedObserver.onError(SerializedObserver.java:153)
       at io.reactivex.internal.operators.observable.ObservableConcatMap$SourceObserver.onError(ObservableConcatMap.java:142)
       at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.tryOnError(ObservableCreate.java:84)
       at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onError(ObservableCreate.java:72)
       at it.mypackage.data.source.aws.LegDataSourceLegsListener.onFailure(LegADataSource.java:760)
       at com.apollographql.apollo.GraphQLCall$Callback.onNetworkError(GraphQLCall.java:135)
       at com.apollographql.apollo.internal.RealAppSyncCall$1.onFailure(RealAppSyncCall.java:259)
       at com.apollographql.apollo.internal.interceptor.ApolloCacheInterceptor$1$1.onFailure(ApolloCacheInterceptor.java:108)
       at com.apollographql.apollo.internal.interceptor.ApolloParseInterceptor$1.onFailure(ApolloParseInterceptor.java:94)
       at com.apollographql.apollo.internal.interceptor.ApolloServerInterceptor$1$1.onFailure(ApolloServerInterceptor.java:105)
       at okhttp3.RealCall$AsyncCall.run(RealCall.kt:146)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
       at java.lang.Thread.run(Thread.java:764)

The error seems to come from this snippet:

@Override
public void onFailure(@Nonnull ApolloException e) {
     if (!emitter.isDisposed()) {
           emitter.onError(e); // here's the problem
     }
}

Now the thing is that ApolloException is not null, also checking the implementation I can tell that it shouldn't be possible to have null as argument of the onFailure.

callBack.onFailure(new ApolloNetworkException("Failed to execute http call", e));

So, where does that error come from?
Any idea?

NOTE: I am using RxJava2, version 2.3.4


Solution

  • The NullPointerException is coming specifically from SingleOnErrorReturn$OnErrorReturn.OnError:

            public void onError(Throwable e) {
                T v;
    
                if (valueSupplier != null) {
                    try {
                        v = valueSupplier.apply(e);
                    } catch (Throwable ex) {
                        Exceptions.throwIfFatal(ex);
                        observer.onError(new CompositeException(e, ex));
                        return;
                    }
                } else {
                    v = value;
                }
    
                if (v == null) {
                    NullPointerException npe = new NullPointerException("Value supplied was null");  // This is the exception you're hitting
                    npe.initCause(e);
                    observer.onError(npe);
                    return;
                }
    
    

    The v it is complaining about is the value that was actually passed to the onErrorReturn(T value) operator. The value passed is null, which is not allowed.

    So I would look for an onErrorReturn operator downstream from t.mypackage.data.source.aws.LegDataSourceLegsListener.onFailure, which is taking a null value. It looks like it will appear right after a .delaySubscription(Completable) operator, based on the stack trace.