Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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) 
like image 434
Djangow Avatar asked Nov 01 '17 14:11

Djangow


1 Answers

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()
like image 166
zsmb13 Avatar answered Nov 14 '22 23:11

zsmb13