Modelling errors

Architecture and dependency injection Mid-level Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Pick the fix

The ViewModel shows e.message to users, which reads 'HTTP 503 Service Unavailable'. Best fix?

Options
Hint 1 of 1

Who should know what HTTP 503 means?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Map exceptions to app errors in the repository and show a message per error type in the UI

Correct. Users get useful text and the UI doesn't depend on HTTP details.

Why not the others?
  • B Catch Exception and show 'Something went wrong' for everything. Loses the difference between offline and server errors.
  • C Hide all errors. Users need to know when something failed.
  • D Throw a RuntimeException with a nicer message. Still an exception crossing layers.

30-second answer

Catch exceptions at the boundary where you can act on them, usually in the repository or ViewModel, and turn them into a typed result the UI can render: a sealed Result/Outcome type or an error field in UiState. Map low-level exceptions (IOException, HttpException) to app-level errors like Offline or NotFound, and keep messages and retry logic out of the data layer's types.

Practise saying it · 30 s. No recording, just a timer

Explain how to model errors.

Say your answer out loud, then check which of these points you covered:

  • Catch at the boundary
  • Map to app-level errors
  • Typed results or UiState error
  • Don't swallow cancellation

Deep dive

Kotlin's Result is fine for simple cases; a sealed interface is clearer when errors have different data.

Never let CancellationException turn into an error result.

Show a retry for transient errors and a different message for permanent ones.

Log unexpected errors to crash reporting even when you show a friendly message.

App-level errors Compile-checked · Kotlin 2.4.21
sealed interface LoadError {
    data object Offline : LoadError
    data object NotFound : LoadError
    data class Unexpected(val cause: Throwable) : LoadError
}

fun Throwable.toLoadError(): LoadError = when (this) {
    is java.io.IOException -> LoadError.Offline
    else -> LoadError.Unexpected(this)
}

Common mistakes

  • Showing exception messages to users.
  • Catching everything with runCatching, including cancellation.
  • Letting exceptions crash the app from viewModelScope.

Senior take & follow-ups

Mention mapping at the boundary and cancellation; both show depth.

Follow-up questions

Think of your answer first, then open the hint.

  1. Result or sealed type?

    Show hint

    Result for success/failure; sealed when errors need different handling.

  2. Where should HttpException be mapped?

    Show hint

    In the repository, so higher layers don't depend on Retrofit.

Similar on iOS: Result and typed throws Swift has typed throws; Kotlin uses sealed types or Result.

Suggest a fix if something here is wrong or out of date.