Creating custom error types is an important skill when designing clear APIs for iOS and macOS applications. This post presents examples for creating, extending, throwing, and catching custom error types in Swift:

  1. Create A Custom Error And Conform To The Error Type
  2. Extend A Custom Error
  3. description for Custom Errors Using CustomStringConvertible
  4. localizedDescription For Custom Errors Using LocalizedError
  5. Throw Custom Errors
  6. Catch Custom Errors

Create A Custom Error And Conform To The Error Type

To create a custom error, create an enum in Swift that conforms to the Error protocol. Each case of the enum represents a unique error that can be thrown and handled:

enum CustomError: Error {
    // Throw when an invalid password is entered
    case invalidPassword

    // Throw when an expected resource is not found
    case notFound

    // Throw in all other cases
    case unexpected(code: Int)
}

Extend A Custom Error

Like all Swift types, new custom error types you create can be extended to add computed properties and functions. In this example, the isFatal computed property is added that can be used to determine if the error is recoverable:

extension CustomError {
    var isFatal: Bool {
        if case CustomError.unexpected = self { return true }
        else { return false }
    }
}

description for Custom Errors Using CustomStringConvertible

Custom errors implemented in Swift can have custom descriptions for each error. To add a description to a new error type, extend the custom error to conform to CustomStringConvertible and add a property description:

// For each error type return the appropriate description
extension CustomError: CustomStringConvertible {
    public var description: String {
        switch self {
        case .invalidPassword:
            return "The provided password is not valid."
        case .notFound:
            return "The specified item could not be found."
        case .unexpected(_):
            return "An unexpected error occurred."
        }
    }
}

localizedDescription For Custom Errors Using LocalizedError

New custom errors you create in Swift can also have localized custom descriptions for each error. To add a localized description to a new error type, extend the custom error to conform to LocalizedError and add a property errorDescription:

// For each error type return the appropriate localized description
extension CustomError: LocalizedError {
    public var errorDescription: String? {
        switch self {
        case .invalidPassword:
            return NSLocalizedString(
                "The provided password is not valid.", 
                comment: "Invalid Password"
            )
        case .notFound:
            return NSLocalizedString(
                "The specified item could not be found.", 
                comment: "Resource Not Found"
            )
        case .unexpected(_):
            return NSLocalizedString(
                "An unexpected error occurred.", 
                comment: "Unexpected Error"
            )
        }
    }
}

Throw Custom Errors

Functions marked as throws in Swift can throw custom errors directly:

func isAvailable(resourcePath path: String) throws -> Bool {
    if FileManager.default.fileExists(atPath: path) { 
        return true 
    }
    else {
        throw CustomError.notFound
    }
}

Catch Custom Errors

Custom errors can be individually caught and handled using the do catch syntax. Use catch followed by the specific error to catch the error and apply specific handling logic:

func open(resourcePath: String) {
    do {
        try isAvailable(resourcePath: resourcePath)
        // Handle opening the resource
    }
    catch CustomError.notFound {
        // Handle custom error
    }
    catch {
        // Handle other errors
    }
}

Create Your Own Errors In Swift

That’s it! By conforming to Error, CustomStringConvertible, and LocalizedError you can implement descriptive, clear, and actionable custom errors in Swift.