okhttp: Okhttp Non IOException handling for Enqueue

As I started to implement coroutines with Okhttp I migrated some calls from execute() to enqueue() to have cancellable Coroutines.

So far all is working well, with worker pool and everything, and then comes the non IO related exceptions that where not tested and are not handled by OkHttp at all when using enqueue.

The problem is that the crash occurs in Okhttp threads and so can’t be intercepted properly by the application.

Caused by android.system.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
       at libcore.io.IoBridge.isConnected(IoBridge.java:267)
       at libcore.io.IoBridge.connectErrno(IoBridge.java:187)
       at libcore.io.IoBridge.connect(IoBridge.java:129)
       at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:137)
       at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
       at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
       at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
       at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
       at java.net.Socket.connect(Socket.java:621)
       at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:1)
       at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:81)
       at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:23)
       at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:120)
       at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:15)
       at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:8)
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:6)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:12)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:1)
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:105)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:12)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:1)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:62)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:12)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:75)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:12)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:1)
       at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:23)
       at okhttp3.RealCall$AsyncCall.execute(RealCall.java:1)
       at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:3)
       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:764)

This user is probably rooted and have disabled internet permission by default, but application should be able to handle that. And there’s a few other errors that are common and Android and require handling.j

This was reported before https://github.com/square/okhttp/issues/3477 and the answer was we can’t handle that as it’s OS error, but I’m not sure the problem was correctly description in the issue naming and description and that after the user explained more in the issue it was not really analysed after. (There’s a second similar issue https://github.com/square/okhttp/issues/3465 that was close for the more or less same reason).

The fix proposed by the user to add an interceptor works, but when using generic reusable component this means that for each request I need to newbuilder.addinterceptor.build this is not efficient and that I lose the original exception for some exceptions I can parse the message and guess, but having the proper exception is better.

I’d like to request a way to properly handle those directly from OKhttp, I understand that it will be complex as interface default do not exist in Java for Android and that changing the callback exception type would not be binary compatible. But I hope there’s a way I did not thought about 😃 Errors happens on Android, application can handle them in synchronous ways by catching them and OkHttp should allow the app to get those and do something instead of crashing in place where the app can’t intercept.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 20 (19 by maintainers)

Most upvoted comments

After discussion with Coroutine lead, probable cause is described at https://github.com/Kotlin/kotlinx.coroutines/issues/830 with some experimental workaround until proper way is made.

I have no idea why the stacktrace is fully the original and not wrapped in anything, but sounds like the only possible explanation.

OkHTTP does not offer an UncaughtExceptionHandler in it’s API or can’t find it.

If you talk about the global UncaughtExceptionHandler then not really, I do want the app to crash when I made mistake or assume thing that I can handle. Or catch them when I can’t and it does not impact the application.

The issue here is that the crash occurs in a place where application can’t do anything about it. For an app that fully support offline mode, it should not crash because there’s no route and OS generate a non IO Exception on some devices.

Anyway the interceptor way works, so it’s OK for me as cost is not that important when I put it in the main app and not the final module who make the call, so while I still think OkHTTP should handle that I won’t fight 😃