---
description: Swift Error Handling
alwaysApply: false
---

# Swift Error Handling

Typed errors, Result, and defensive validation. Make failure states explicit.

## Error Types

```swift
enum APIError: Error, LocalizedError {
    case networkUnavailable
    case notFound(resource: String, id: String)
    case serverError(statusCode: Int, message: String)

    var errorDescription: String? {
        switch self {
        case .networkUnavailable: "Network unavailable"
        case .notFound(let r, let id): "\(r) '\(id)' not found"
        case .serverError(let code, let msg): "Server error \(code): \(msg)"
        }
    }
}
```

## do/catch

```swift
do {
    let user = try await userService.fetch(id: id)
    self.user = user
} catch let error as APIError {
    switch error {
    case .notFound: self.state = .notFound
    case .networkUnavailable: self.state = .offline
    default: self.state = .error(error)
    }
} catch {
    self.state = .error(AppError.unexpected(error))
}

// try? — convert to optional; try! — only for programmer errors
let regex = try! NSRegularExpression(pattern: "^[a-z]+$")
```

## Result Type

```swift
func validate(email: String) -> Result<Email, ValidationError> {
    guard !email.isEmpty else { return .failure(.empty("email")) }
    guard email.contains("@") else { return .failure(.invalidFormat("email")) }
    return .success(Email(rawValue: email))
}
```

## Guard Pattern

```swift
func processOrder(_ order: Order) throws {
    guard !order.items.isEmpty else { throw OrderError.emptyOrder }
    guard order.status == .confirmed else { throw OrderError.invalidStatus(order.status) }
    guard let payment = order.paymentMethod else { throw OrderError.noPaymentMethod }
    charge(payment, for: order)
}
```

## Anti-Patterns

```swift
// Never: catching and ignoring — do { try op() } catch { }
// Never: try! on fallible operations — crash on failure
// Never: throwing generic Error/NSError without context
// Never: error types without associated values for debugging
```
