fix(core:data): catch deserialization errors in safeCall (review)

Deserialization happens in responseToResult via response.body<T>() on the 2xx branch.
That call was outside safeCall's try/catch, so a malformed 2xx body threw an uncaught
SerializationException (crash) instead of mapping to DataError.Network.SERIALIZATION.
Move responseToResult(execute()) inside the try so both transport and parse errors are typed.

Found by the milestone review.
This commit is contained in:
2026-06-10 11:57:08 +02:00
parent 070ffde49c
commit b7ccf2fefa

View File

@@ -54,27 +54,30 @@ suspend inline fun <reified Response : Any> HttpClient.delete(
}
}
/** Wraps a Ktor call, turning transport exceptions into typed [DataError.Network] results. */
/**
* Wraps a Ktor call AND its response deserialization, turning transport/parse exceptions into typed
* [DataError.Network] results. `responseToResult` runs inside the try so a malformed 2xx body maps
* to SERIALIZATION instead of escaping uncaught.
*/
suspend inline fun <reified T> safeCall(
execute: () -> HttpResponse,
): Result<T, DataError.Network> {
val response = try {
execute()
return try {
responseToResult(execute())
} catch (e: UnresolvedAddressException) {
KermitLogger.withTag("HttpClient").e(e) { "No internet (unresolved address)" }
return Result.Error(DataError.Network.NO_INTERNET)
Result.Error(DataError.Network.NO_INTERNET)
} catch (e: UnknownHostException) {
KermitLogger.withTag("HttpClient").e(e) { "No internet (unknown host)" }
return Result.Error(DataError.Network.NO_INTERNET)
Result.Error(DataError.Network.NO_INTERNET)
} catch (e: SerializationException) {
KermitLogger.withTag("HttpClient").e(e) { "Serialization failure" }
return Result.Error(DataError.Network.SERIALIZATION)
Result.Error(DataError.Network.SERIALIZATION)
} catch (e: Exception) {
if (e is CancellationException) throw e
KermitLogger.withTag("HttpClient").e(e) { "Unknown network failure" }
return Result.Error(DataError.Network.UNKNOWN)
Result.Error(DataError.Network.UNKNOWN)
}
return responseToResult(response)
}
/** Maps HTTP status codes to typed [DataError.Network] (extends the skill table with 400/403/404). */