100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Swift

Error Handling in Swift

Learn how Swift represents, throws, propagates, and handles runtime errors using the Error protocol and try/catch.

Error Handling & ConcurrencyIntermediate9 min readJul 8, 2026
Analogies

Introduction

Swift provides first-class support for handling recoverable runtime errors. Instead of returning special sentinel values or crashing, functions that can fail are marked with the throws keyword and describe their failure using types that conform to the Error protocol. This lets the compiler enforce that callers acknowledge and handle possible failures, making error paths explicit and easy to trace through code.

🏏

Cricket analogy: A run-chase calculator marked as able to 'fail' when the required run rate becomes impossible is like a function marked throws, forcing the scorer to explicitly handle the 'match lost' case rather than silently returning a wrong number.

Syntax

swift
enum ValidationError: Error {
    case tooShort
    case containsInvalidCharacters
}

func validate(username: String) throws -> Bool {
    if username.count < 3 {
        throw ValidationError.tooShort
    }
    return true
}

do {
    try validate(username: "ab")
} catch {
    print("Validation failed: \(error)")
}

Explanation

ValidationError is an enum conforming to Error, which is the typical way to model a closed set of failure cases. The validate function is marked throws, signaling it may fail instead of returning normally. Inside, throw immediately exits the function and hands the error to the calling context. A do block wraps any try expressions; if a thrown error propagates out, execution jumps to the matching catch block, where the error is available as the implicit error constant unless you bind it to a named pattern.

🏏

Cricket analogy: A NoBallError enum conforming to Error models illegal deliveries; a checkDelivery function marked throws calls throw NoBallError.overstepping the instant the bowler oversteps, and the umpire's do/catch block catches it via the implicit error constant to signal a free hit.

Example

swift
enum NetworkError: Error {
    case badURL
    case timeout
}

func fetch(urlString: String) throws -> String {
    guard urlString.hasPrefix("https://") else {
        throw NetworkError.badURL
    }
    return "data from \(urlString)"
}

// try? converts the result into an Optional
let result = try? fetch(urlString: "ftp://example.com")
print(result ?? "no data")

// try! force-unwraps, crashing on failure
let forced = try! fetch(urlString: "https://example.com")
print(forced)

do {
    let value = try fetch(urlString: "bad")
    print(value)
} catch NetworkError.badURL {
    print("The URL was malformed")
} catch {
    print("Unexpected error: \(error)")
}

Output

swift
no data
data from https://example.com
The URL was malformed

Key Takeaways

  • Errors are values conforming to the Error protocol, usually modeled as enums with associated cases.
  • Functions that can fail are marked throws and must be called with try inside a do/catch, or with try?/try!.
  • do/catch blocks can pattern-match specific error cases before falling back to a generic catch.
  • try? converts a throwing call into an Optional, returning nil on failure instead of propagating the error.
  • try! force-tries a call and crashes the program at runtime if it throws, so use it only when failure is truly impossible.
  • Explicit error handling makes failure paths visible in code and enforced by the compiler.

Practice what you learned

Was this page helpful?

Topics covered

#Swift#SwiftProgrammingStudyNotes#Programming#ErrorHandlingInSwift#Error#Handling#Syntax#Explanation#ErrorHandling#StudyNotes#SkillVeris