Skip to content
AB
1 min readIntermediateReliable Swift Networking · Part 1

Typed Errors in Swift: User Messages and Telemetry Codes

Model failures by recovery behavior while separating safe UI copy from stable operational identifiers.

Ashish BhakhandPublished

Showing error.localizedDescription exposes messages written by frameworks, providers, or the backend. They are inconsistent and may contain details users should never see.

I map failures into one application vocabulary:

Code
enum AppError: Error, Equatable {
    case network(Network)
    case auth(Auth)
    case server(Server)
    case storage(Storage)
    case validation(field: String, message: String)
    case unknown(code: String, debugMessage: String)
}

Each failure provides two different contracts:

Code
extension AppError {
    var userMessage: String { /* safe, helpful copy */ }
    var telemetryCode: String { /* stable machine identifier */ }
}

The UI reads only userMessage. Logs and analytics use telemetryCode. Debug context stays out of both unless a protected diagnostic channel explicitly accepts it.

Types should reflect recovery. Offline, timeout, expired session, rate limit, and decoding failures lead to different behavior. A single .somethingWentWrong case throws away information the reducer needs.

Map errors at boundaries. URLSession errors become network cases, API envelopes become server cases, and SwiftData errors become storage cases. Application code should not switch on every framework's error type.

Typed throws can document a client contract, but the important result is consistent meaning. A feature can decide whether to retry, sign out, request permission, or show validation feedback without parsing strings.

← Back to all writing