2

I searched for NullPointerException: Plugin returned null Observer, but didn't find any helpful fix. I found this issue in Crashlytics so I have no scenario to create it. The complete error is as follow:

Fatal Exception: java.lang.NullPointerException: Plugin returned null Observer
       at io.reactivex.d.b.am.a(ObjectHelper.java:39)
       at io.reactivex.k.subscribe(Observable.java:12049)
       at io.reactivex.d.e.d.go.subscribeActual(ObservableObserveOn.java:45)
       at io.reactivex.k.subscribe(Observable.java:12051)
       at io.reactivex.k.subscribe$209b3d11(Observable.java:12037)
       at io.reactivex.k.subscribe$50b5b765(Observable.java:11997)
       at com.example.mobile.feature.home_serp.AbsSerpPresenter.observeAction(AbsSerpPresenter.kt:365)
       at com.example.mobile.fragments.f.a(Unknown Source:1489)
       at com.example.mobile.feature.home_serp.SerpAdapter.onCreateViewHolder(SerpAdapter.kt:39)
       at com.example.mobile.feature.home_serp.SerpAdapter.onCreateViewHolder(SerpAdapter.kt:17)
       at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6685)
       at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5869)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5752)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5748)
       at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2232)
       at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:556)
       at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1519)
       at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:614)
       at android.support.v7.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
       at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3812)
       at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3529)
       at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:4082)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:606)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:132)
       at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
       at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1361)
       at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:894)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.widget.RelativeLayout.onLayout(RelativeLayout.java:925)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:132)
       at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
       at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1361)
       at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:894)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1644)
       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1502)
       at android.widget.LinearLayout.onLayout(LinearLayout.java:1415)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1644)
       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1502)
       at android.widget.LinearLayout.onLayout(LinearLayout.java:1415)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
       at android.view.View.layout(View.java:11420)
       at android.view.ViewGroup.layout(ViewGroup.java:4238)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1671)
       at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2628)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:137)
       at android.app.ActivityThread.main(ActivityThread.java:4517)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:511)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
       at dalvik.system.NativeStart.main(NativeStart.java)

We have these dependencies:

implementation 'io.reactivex.rxjava2:rxkotlin:2.2.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.1.14'

I read the RxJava code and the assertion is in subscribe method as follow:

    @SchedulerSupport(SchedulerSupport.NONE)
    @Override
    public final void subscribe(Observer<? super T> observer) {
        ObjectHelper.requireNonNull(observer, "observer is null");
        try {
            observer = RxJavaPlugins.onSubscribe(this, observer);

            ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");

            subscribeActual(observer);
        } catch (NullPointerException e) { // NOPMD
            throw e;
        } catch (Throwable e) {
            Exceptions.throwIfFatal(e);
            // can't call onError because no way to know if a Disposable has been set or not
            // can't call onSubscribe because the call might have set a Subscription already
            RxJavaPlugins.onError(e);

            NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS");
            npe.initCause(e);
            throw npe;
        }
    }

Also the code of onSubscribe method is as follow:

    /**
     * Calls the associated hook function.
     * @param <T> the value type
     * @param source the hook's input value
     * @param observer the observer
     * @return the value returned by the hook
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @NonNull
    public static <T> Observer<? super T> onSubscribe(@NonNull Observable<T> source, @NonNull Observer<? super T> observer) {
        BiFunction<? super Observable, ? super Observer, ? extends Observer> f = onObservableSubscribe;
        if (f != null) {
            return apply(f, source, observer);
        }
        return observer;
    }

So the apply method returns null, which is onObservableSubscribe.apply(source, observer). I stoped here!

This is the code that we use to subscribe:

fun observeAction(observable: Observable<BaseAction>) {
    if (mSubject == null) {
        mSubject = PublishSubject.create()
        mSubject!!.throttleFirst(1100, TimeUnit.MILLISECONDS)
                .subscribe(onNextObserver(),
                        { t: Throwable -> logger.e("Cannot receive the action", t) },
                        { logger.e("action receiver is completed") })
    }

    mSubscriptionsLongLife.add(
            observable.observeOn(AndroidSchedulers.mainThread())
                    .subscribe(mSubject!!::onNext, mSubject!!::onError, mSubject!!::onComplete)
    )
}

private fun onNextObserver(): (BaseAction) -> Unit {
    return { action ->
        blah blah ...
    }
}

Any suggestion to fix the bug would help.

hadilq
  • 1,023
  • 11
  • 25
  • 1
    have you tried taking a look at the line : AbsSerpPresenter.observeAction(AbsSerpPresenter.kt:365) ? – mariuss Aug 25 '18 at 09:21
  • see `com.example.mobile.feature.home_serp.AbsSerpPresenter.observeAction(AbsSerpPresenter.kt:365)` and set a break-point there. and that `@SuppressWarnings` annotation also looks suspicious. – Martin Zeitler Aug 25 '18 at 09:32
  • @msapinu This bug doesn't have a scenario, which means this method is working fine in my machine. Also if you look on RxJava code you may notice that if observer was null in the first place, I would get "observer is null" assertion instead, that I'm not. Thank you for your suggestions. – hadilq Aug 25 '18 at 09:42
  • @Martin Zeitler Thank you but this method is working fine. Have you any suggestion to find out what may gets wrong about `@SuppressWarnings`? – hadilq Aug 25 '18 at 09:46
  • @hadilq this is what you may believe, while the stack-trace tells the opposite... and your question does not contain any `AbsSerpPresenter#observeAction()` ...which might get passed an `Observer`, which is `NULL`. – Martin Zeitler Aug 25 '18 at 09:51
  • @MartinZeitler My friend, this in not a belief. This is a fact that `ObjectHelper.requireNonNull(observer, "observer is null");` is not thrown any error, so observer is not null. – hadilq Aug 25 '18 at 10:09
  • Somebody has installed an `onSubscribe` hook that is not returning a valid hooked `Observer`. Check your source & dependencies for `RxJavaPlugins.setOnObservableSubscribe` call and see why it returns null. – akarnokd Aug 25 '18 at 10:10
  • @hadilq it clearly reads `Plugin returned null Observer` coming from `observer = RxJavaPlugins.onSubscribe(this, observer);` ...set a condition break-point for `observer == null` at `return observer;` in method `onSubscribe()`. – Martin Zeitler Aug 25 '18 at 10:11
  • @akarnokd Thank you. I checked it out and `RxJavaPlugins.setOnObservableSubscribe` is only called from `RxJavaPlugins.reset();` method inside the test suite, so it cannot be in `Crashlytics` errors from users! – hadilq Aug 25 '18 at 10:17
  • If it is not in your code, you may be using some tools that are setting this type of hook. What are your dependencies? Are you using `RxJavaPlugins` in any way? – akarnokd Aug 25 '18 at 10:35
  • @akarnokd I updated the question and added more dependencies, that I think, are related to the RxJava. I'll look more for the probable usage of RxJavaPlugins. Thank you. – hadilq Aug 25 '18 at 10:52
  • None of those dependencies set up an `onSubscribe` hook. Are you using any RxJava-debugging or tracing libraries? – akarnokd Aug 25 '18 at 10:56
  • @akarnokd not using RxJava-debugging! – hadilq Aug 25 '18 at 13:19
  • Is the error happening at that specific point all the time? I suggest logging the `RxJavaPlugins.getOnObservableSubscribe()`'s value (i.e., the returned object's `getClass()`) to see what has been set up as hook. – akarnokd Aug 25 '18 at 13:26
  • @akarnokd That's a good idea. I'll try that tomorrow. – hadilq Aug 25 '18 at 15:21
  • I added the log, but we have to release our app to get the logs!! So it take a while to update this question. – hadilq Aug 26 '18 at 07:10

0 Answers0