Skip to content

UndeliverableException in very rare cases #315

@L-Andrade

Description

@L-Andrade

Hello,

We are using the Contentful SDK, and very rarely we get a crash with the following stack trace:

Fatal Exception: io.reactivex.rxjava3.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.ConnectException: Failed to connect to cdn.contentful.com/151.101.39.18:443
       at io.reactivex.rxjava3.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:372)
       at io.reactivex.rxjava3.internal.subscribers.LambdaSubscriber.onError(LambdaSubscriber.java:85)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowablePublish$PublishConnection.signalError(FlowablePublish.java:367)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowablePublish$PublishConnection.checkTerminated(FlowablePublish.java:350)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowablePublish$PublishConnection.drain(FlowablePublish.java:302)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowablePublish$PublishConnection.onError(FlowablePublish.java:244)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runBackfused(FlowableObserveOn.java:450)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(FlowableObserveOn.java:174)
       at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:80)
       at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java)
       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:923)
        
Caused by java.net.ConnectException: Failed to connect to cdn.contentful.com/151.101.39.18:443
       at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:297)
       at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
       at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
       at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
       at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
       at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.java:255)
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:76)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at com.contentful.java.cda.interceptor.ErrorInterceptor.intercept(ErrorInterceptor.java:31)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at com.contentful.java.cda.interceptor.HeaderInterceptor.intercept(HeaderInterceptor.java:38)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at com.contentful.java.cda.interceptor.HeaderInterceptor.intercept(HeaderInterceptor.java:38)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at com.contentful.java.cda.interceptor.HeaderInterceptor.intercept(HeaderInterceptor.java:38)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
       at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
       at retrofit2.OkHttpCall.execute(OkHttpCall.java:207)
       at retrofit2.adapter.rxjava3.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:46)
       at io.reactivex.rxjava3.core.Observable.subscribe(Observable.java:13263)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableFromObservable.subscribeActual(FlowableFromObservable.java:31)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16149)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16095)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:161)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:69)
       at io.reactivex.rxjava3.internal.subscriptions.ScalarSubscription.request(ScalarSubscription.java:55)
       at io.reactivex.rxjava3.internal.subscribers.BasicFuseableSubscriber.request(BasicFuseableSubscriber.java:153)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onSubscribe(FlowableFlatMap.java:115)
       at io.reactivex.rxjava3.internal.subscribers.BasicFuseableSubscriber.onSubscribe(BasicFuseableSubscriber.java:67)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableScalarXMap$ScalarXMapFlowable.subscribeActual(FlowableScalarXMap.java:158)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16149)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:38)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16149)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableFlatMap.subscribeActual(FlowableFlatMap.java:51)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16149)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:38)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16149)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowableObserveOn.subscribeActual(FlowableObserveOn.java:58)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16149)
       at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:16095)
       at io.reactivex.rxjava3.internal.operators.flowable.FlowablePublish.connect(FlowablePublish.java:93)
       at io.reactivex.rxjava3.flowables.ConnectableFlowable.connect(ConnectableFlowable.java:105)
       at com.contentful.java.cda.Callbacks.subscribeAsync(Callbacks.java:21)
       at com.contentful.java.cda.FetchQuery.all(FetchQuery.java:63)
       at (our app's package)$suspendedAll$2.invokeSuspend(ContentfulFetcher.kt:82)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
       at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.java:113)
       at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
       at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:586)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:820)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704)
        

It seems to be RxJava related. We're not doing anything in particular, we're just registering a FetchQuery with the all method. Something like:

private suspend fun <T : CDAResource> FetchQuery<T>.suspendedAll(): List<CDAResource> {
    val callback = object : CDACallback<CDAArray>() {
        override fun onSuccess(result: CDAArray) {
            // Success
        }

        override fun onFailure(error: Throwable?) {
            // Fail
        }
    }
    // More code here where we might cancel the callback (via a Coroutines cancellation for example)
    all(callback)
}

Which is then used like:

client.fetch(CDAEntry::class.java)
    .withContentType(contentType)
    .include(level)
    .where(/* some custom code here */)
    .suspendedAll()

Again, this happens very rarely - 3 times in the last 30 days, with slightly different network errors - and we have not been able to reproduce it. Querying Contentful with the device's network disabled just goes to the usual onFailure. But on very rare cases, it crashes in the all call, with a stack trace like the above - which we find on our crash monitoring.

Let me know if you need any further details on our implementation - sadly I can not share the actual code.

Thanks in advance!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions