Djangow
Djangow

Reputation: 391

Retrofit crashes when I throw an exception in an interceptor

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) 

Upvotes: 29

Views: 9812

Answers (2)

聂超群
聂超群

Reputation: 2120

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

Upvotes: 2

zsmb13
zsmb13

Reputation: 89548

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()

Upvotes: 43

Related Questions