Error handling
Skill thetruong1099/android-mvi-base-code/.claude/skills/error-handling
npx -y skills add thetruong1099/android-mvi-base-code --skill error-handlingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Error handling flow from data layer to UI. Use when implementing AppError handling in ViewModels with showErrorToast, adding new error types to AppError sealed class, extending ExceptionMapper for new infrastructure exceptions, extending ErrorHandler for new UI messages, or understanding the complete Exception to AppError to Toast flow.
SKILL.md
4.7 KB, as published. Nobody here has run it
Error Handling
Architecture
Data Layer Domain Layer Presentation Layer
ExceptionMapper --> AppError (sealed) --> ErrorHandler
(Exception -> domain) (in DataState) (AppError -> string res)
AppError (domain/core)
sealed class AppError {
abstract val loggableMessage: String? // For logging ONLY, never show to users
// Network
data class NoInternetConnection(...) : AppError()
data class NetworkTimeout(...) : AppError()
data class ServerError(val statusCode: Int, ...) : AppError()
// Data
data class DataParsingError(val exception: Exception, ...) : AppError()
// Auth
data class Unauthorized(...) : AppError()
// Generic
data class Unknown(val exception: Throwable? = null, ...) : AppError()
}
ExceptionMapper (data/core)
Maps infrastructure exceptions to AppError. Used internally by BaseDataSource strategies — do NOT call from presentation layer.
SocketTimeoutException -> AppError.NetworkTimeout
IOException -> AppError.NoInternetConnection
HttpException(401) -> AppError.Unauthorized
HttpException(400-499) -> AppError.ServerError(statusCode)
HttpException(500-599) -> AppError.ServerError(statusCode)
JsonEncodingException -> AppError.DataParsingError
JsonDataException -> AppError.DataParsingError
Other -> AppError.Unknown
ErrorHandler (feature/core)
fun getErrorMessageResId(error: AppError): Int = when (error) {
is AppError.NoInternetConnection -> R.string.no_connect_internet
is AppError.NetworkTimeout -> R.string.network_timeout
is AppError.Unauthorized -> R.string.unauthorized
is AppError.ServerError -> R.string.server_error
is AppError.DataParsingError -> R.string.data_error
// ...
}
Error Flow Patterns
Pattern 1: DataState Flow (most common)
// Data layer handles automatically via strategy classes
// ViewModel:
viewModelScope.launch {
collectDataStateWithInternet(
callFlow = useCase(params),
onSuccess = { data -> setState { copy(detail = data) } },
onError = { error -> showErrorToast(error) },
)
}
Pattern 2: PagingData Flow
val result = callPagingDataWithInternet(
callFlow = { useCase() },
onError = { error -> showErrorToast(error) },
).cachedIn(viewModelScope)
Pattern 3: Suspend operations
viewModelScope.launch {
callSuspendWithInternet(
operation = { useCase(params) },
onSuccess = { setState { copy(saved = true) } },
onError = { error -> showErrorToast(error) },
)
}
When to Use Which Function
| Scenario | Function | Internet Check |
|---|---|---|
| PagingData from network | callPagingDataWithInternet() | Yes |
| PagingData from local | callPagingDataWithoutInternet() | No |
| DataState flow from network | collectDataStateWithInternet() | Yes |
| DataState flow from local | collectDataState() | No |
| One-shot network operation | callSuspendWithInternet() | Yes |
| One-shot local operation | callSuspendWithoutInternet() | No |
| Regular flow collection | collectFlowWithInternet() | Yes |
Adding a New Error Type
- Add to
AppErrorindomain/core:
data class NewErrorType(
override val loggableMessage: String? = "Description"
) : AppError()
- Map in
ExceptionMapper(if from infrastructure exception):
is MyCustomException -> AppError.NewErrorType(...)
- Map in
ErrorHandler:
is AppError.NewErrorType -> R.string.new_error_message
- Add string resource in
feature/core/src/main/res/values/strings.xml
Toast Display
// In ViewModel - automatically maps AppError -> localized string -> toast
showErrorToast(appError) // Red toast
showSuccessToast(R.string.saved) // Green toast
showWarningToast(R.string.warning) // Yellow toast
showInfoToast(R.string.info) // Blue toast
Toast displayed via ToastHost provided by TemplateTheme.