# Exceptions and proxies and coroutines, oh my!

DevFeed: [Exceptions and proxies and coroutines, oh my!](<https://devfeed.tech/articles/exceptions-and-proxies-and-coroutines-oh-my-20934.md>)

Original publisher: [Read original article](<https://jakewharton.com/exceptions-and-proxies-and-coroutines-oh-my/>)

Published: 2019-07-31T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [Exception](<https://devfeed.tech/topics/exception.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Java](<https://devfeed.tech/topics/java.md>), [HTTP](<https://devfeed.tech/topics/http.md>)

Tags: [coroutines](<https://devfeed.tech/tags/coroutines.md>), [exception](<https://devfeed.tech/tags/exception.md>), [http](<https://devfeed.tech/tags/http.md>), [java](<https://devfeed.tech/tags/java.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>)

## AI overview

The article explains how checked exceptions interact with Java Proxy and Kotlin coroutines in Retrofit. It examines why exceptions can be thrown synchronously despite coroutine methods being rewritten to use Continuation callbacks, and how suspension and asynchronous result delivery affect exception propagation.

## Source excerpt

Checked exceptions are a concept that exist only in the Java compiler and are enforced only in source code. In Java bytecode and at runtime in the virtual machine you're free to throw checked exceptions from anywhere regardless of whether they're declared. At least, anywhere except from a instance created by a Java Proxy. A Proxy creates instances of interfaces at runtime where a single callback intercepts every method call. Libraries like Retrofit use proxies to create HTTP calls based on the annotations of interface methods. These methods tend to return promise-like objects such as RxJava's Single, Guava's ListenableFuture, or its own Call type. // MyService.java interface MyService { @GET("/user/{id}") Call<User> user(@Path("id") long id); } Retrofit recently added support for Kotlin coroutines' suspend functions which behave a bit differently. Aside from the suspend modifier, the method signature otherwise appears synchronous. // MyService.kt interface MyService { @GET("/user/{id}") suspend fun user(@Path("id") id: Long): User } Kotlin does not require declaring checked exceptions. With Retrofit using a Proxy and performing a network call that may throw an IOException, you might expect to be required to declare @Throws(IOException::class) though. This isn't actually required because the method signature gets rewritten by the Kotlin compiler to accept a Continuation parameter where both exceptions and results are forwarded. // Approximate Java for the compiled bytecode of MyService.kt: interface MyService { void user(@Path("id") long id, Continuation<? super User> continuation); } Despite rewriting the bytecode to be callback-based and Retrofit asynchronously invoking the Continuation, rare calls to this method were resulting in an UndeclaredThrowableException. This indicates a checked exception was somehow being synchronously thrown. To understand why this was occurring and to craft a fix, we need to learn more about how coroutines work... Coroutine Implementation