retrofit: UndeclaredThrowableException when using "suspend" modifier
Retrofit crashes with UndeclaredThrowableException when using suspend modifier and making multiple requests which are supposed to throw IOException.
Retrofit version: 2.6.0, 2.6.1-SNAPSHOT (20190612)
class RetrofitUndeclaredThrowableExceptionBug {
interface Service {
@GET("/")
suspend fun download()
}
@Test
fun test() = runBlocking {
val retrofit = Retrofit.Builder()
.baseUrl("https://unresolved-host.com/") // An unresolved host to simulate IOException
.build()
val service = retrofit.create<Service>(Service::class.java)
// First attempt works fine
try {
service.download()
} catch (e: IOException) {
println("Catched 1: $e")
}
// Second attempt sometimes crashes
try {
service.download()
} catch (e: IOException) {
println("Catched 2: $e")
}
// And this will crash for sure (sometimes sooner, sometimes later)
repeat(Integer.MAX_VALUE) {
try {
service.download()
} catch (e: IOException) {
println("Catched 3: $e")
}
}
}
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 9
- Comments: 17 (10 by maintainers)
The same happens when throwing an exception from an interceptor
There should be a fat warning on the release notes, that using
suspendmodifier for retrofit is not production ready.Network calls can throw checked
IOExceptions so you need to declare@Throws(IOException::class)on every single function on your interface or it will blow up at runtime.I’m still getting the
UndeclaredThrowableExceptionswithin my app. Our Retrofit services returnResponsesinstead of POJOs. My hunch (that I’m about to try and verify) is that you applied the newyieldAndThrowlogic only toSuspendForBodybut didn’t apply the same logic toSuspendForResponse, and our services are using the currently unprotectedSuspendForResponseWhat’s the difference between a wrapping and a non-wrapping adapter? I’d like to test the difference in exceptions handling.
On Wed, Jul 24, 2019, 02:07 Jake Wharton notifications@github.com wrote: