27

I have an interceptor that handles some authentication things. If the authentication fails it throws and Exception. According to what I could find throwing an exception should result in onFailure getting called where I handle the exception. Unfortunatly this does not happen and the app simply crashes completely. I am sure I must be missing something but I cant seem to figure it out. Hope someone here can help :)

Code and stack trace below:

val client = OkHttpClient.Builder()
     // Add interceptor that throws
     .addInterceptor { chain ->
         throw Exception("test")
     }
     .build()

retrofit = Retrofit.Builder()
                .baseUrl(baseURL)
                .client(client)
                .build()

api = retrofit.create(ApiInterface::class.java)


// Create api call...

apicall.enqueue(object : Callback<T> {
    override fun onResponse(call: Call<T>?, response: retrofit2.Response<T>?) {
        // ....
    }

    override fun onFailure(call: Call<T>?, t: Throwable?) {
        // Expect to go here to handle the Exception. But the app crashes
    }
})

Stack trace:

E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
                  Process: com.testapp.test.debug, PID: 28891
                  java.lang.Error: java.lang.Exception: test
                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1168)
                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
                      at java.lang.Thread.run(Thread.java:764)
                   Caused by: java.lang.Exception: test
                      at com.testapp.test.data.networking.RetrofitWebApi$client$1.intercept(RetrofitWebApi.kt:90)
                      at com.testapp.test.data.networking.RetrofitWebApi$client$1.intercept(RetrofitWebApi.kt:76)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                      at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
                      at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)
                      at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                      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) 
Djangow
  • 341
  • 3
  • 9

2 Answers2

39

OkHttp will only catch the exception that happens in the Interceptor if it's an IOException. You can see the code that does this here, the relevant parts (simplified) are as below:

try {
  Response response = getResponseWithInterceptorChain();
} catch (IOException e) {
  responseCallback.onFailure(RealCall.this, e);
}

So if you change your code to the following, you'll get a callback in your onFailure method as expected:

val client = OkHttpClient.Builder()
     // Add interceptor that throws
     .addInterceptor { chain ->
         throw IOException("test")
     }
     .build()
heyheyhey
  • 1,216
  • 8
  • 12
zsmb13
  • 85,752
  • 11
  • 221
  • 226
1

You should never throw exception which is not IOException in OkHttp's Interceptor since it will not handled by OkHttp.

Check below source code from OkHttp's RealCall.java:

enter image description here

聂超群
  • 1,659
  • 6
  • 14