Are you struggling with TimeoutException in your Kotlin API calls? This common issue often occurs when making network requests with Retrofit or OkHttp that take too long to respond. In this guide, you’ll learn how to properly handle timeouts in Kotlin-based Android projects by configuring timeouts correctly and using coroutine best practices.

What Causes TimeoutException?
A TimeoutException usually appears when your API call exceeds the default timeout duration. This is particularly common on slow networks or large payloads. To fix it, you can:
- Set custom timeout values in OkHttpClient.
- Handle exceptions gracefully in
try-catch. - Implement fallback mechanisms.
Sample Fix using Retrofit + Coroutine
1. API Client Configuration (with custom timeout)
// ApiClient.kt import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.util.concurrent.TimeUnit object ApiClient { private const val BASE_URL = "https://jsonplaceholder.typicode.com/" private val client = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build() val instance: ApiService by lazy { Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) } }
2. Define Your API Interface
// ApiService.kt
import retrofit2.http.GET
interface ApiService {
@GET("posts")
suspend fun getPosts(): List<Post>
}
3. Data Model
// Post.kt
data class Post(
val userId: Int,
val id: Int,
val title: String,
val body: String
)
4. Repository with Coroutine Exception Handling
// PostRepository.kt
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.net.SocketTimeoutException
class PostRepository {
suspend fun fetchPosts(): Result<List<Post>> {
return withContext(Dispatchers.IO) {
try {
val posts = ApiClient.instance.getPosts()
Result.success(posts)
} catch (e: SocketTimeoutException) {
Result.failure(Exception("Request timed out. Please try again."))
} catch (e: Exception) {
Result.failure(e)
}
}
}
}
5. Using in ViewModel
// PostViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
class PostViewModel : ViewModel() {
private val repository = PostRepository()
val posts = liveData {
val result = repository.fetchPosts()
emit(result)
}
}
External Reference
Learn more about timeout configuration in OkHttp official documentation.