Swift Academy · Lesson

Error Handling Operators

Recover with catch, retry, and replaceError.

Lesson 3 of 413 steps

Error Handling Operators is a free Swift Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, and your progress syncs across the web and the CoddyKit app. The Swift Academy course includes 4 lessons in total.

Errors in Combine

Combine publishers have a Failure type. When a publisher fails, it terminates the stream — no more values are emitted. To build resilient pipelines you need operators that handle, transform, or recover from errors.

The Failure Type

Every publisher declares an Output and a Failure. A pipeline only compiles when error types align, so operators that change failures are common.

let publisher: AnyPublisher<Data, URLError> = apiClient.request()
// Output = Data, Failure = URLError

catch

catch intercepts a failure and replaces the failed publisher with a new one. This lets you provide fallback values when something goes wrong.

apiClient.fetchUser()
    .catch { error in
        Just(User.guest)
    }
    .sink { user in
        print("Got", user.name)
    }
    .store(in: &cancellables)

replaceError

replaceError(with:) is a simpler form of catch: it swaps any failure for a single fallback value and completes successfully.

apiClient.fetchCount()
    .replaceError(with: 0)
    .sink { count in
        self.badge.text = "\(count)"
    }
    .store(in: &cancellables)

retry

retry(n) re-subscribes to the upstream up to n times when it fails. It is ideal for transient network errors.

apiClient.fetchData()
    .retry(3)
    .sink(receiveCompletion: { print($0) },
          receiveValue: { print($0) })
    .store(in: &cancellables)

Combining retry and catch

A common resilient pattern: retry a few times, then catch to fall back if all attempts fail.

apiClient.fetchData()
    .retry(2)
    .catch { _ in
        Just(Data())
    }
    .sink { data in
        self.process(data)
    }
    .store(in: &cancellables)

mapError

mapError transforms one error type into another. This is essential for unifying different upstream failures into a single app-level error type.

enum AppError: Error { case network }

apiClient.request()
    .mapError { _ in AppError.network }
    .sink(receiveCompletion: { _ in }, receiveValue: { _ in })
    .store(in: &cancellables)

Why mapError Matters

When you combine publishers, their Failure types must match. mapError normalizes mismatched errors so operators like merge and zip compile and so your sink handles one error type.

setFailureType

Some publishers, like Just, have a Never failure type. setFailureType(to:) bridges them so they can combine with failing publishers.

Just(42)
    .setFailureType(to: AppError.self)
    .merge(with: failablePublisher)
    .sink(receiveCompletion: { _ in }, receiveValue: { _ in })
    .store(in: &cancellables)

Handling Completion

In sink, the completion closure tells you whether the stream finished or failed. Inspect it to react to errors that were not recovered upstream.

publisher.sink(
    receiveCompletion: { completion in
        if case .failure(let error) = completion {
            self.showAlert(error)
        }
    },
    receiveValue: { value in
        self.update(value)
    }
).store(in: &cancellables)

Designing Resilient Pipelines

Best practices for error handling:

  • Use retry for transient failures
  • Use catch or replaceError for fallbacks
  • Use mapError to unify error types
  • Always handle the failure case in sink

Quick Check

Test your error handling knowledge.

Recap

You learned Combine error-handling operators:

  • catch / replaceError — provide fallbacks
  • retry — re-attempt on failure
  • mapError / setFailureType — unify error types

Together they let you build pipelines that degrade gracefully instead of dying on the first error.

Free to start

Learn Swift with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
122
Lessons
409

Frequently Asked Questions

Is the “Error Handling Operators” lesson free?

Yes — any 3 lessons of the Swift Academy learning path, including “Error Handling Operators”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Swift Academy course includes 4 lessons in total.

What will I learn in “Error Handling Operators”?

Recover with catch, retry, and replaceError. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “Error Handling Operators” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Transforming and Combining Streams
  2. Schedulers and Threading
  3. Error Handling Operators
  4. Custom Publishers and Subscribers
← Back to Swift Academy