Skip to content

Simplified error handling with built-in user-friendly messages for common errors. Fully localized. Community-driven.

License

Notifications You must be signed in to change notification settings

FlineDev/ErrorKit

Repository files navigation

ErrorKit Logo

ErrorKit

Making error handling in Swift more intuitive and powerful with clearer messages, type safety, and user-friendly diagnostics.

Overview

Swift's error handling has several limitations that make it challenging to create robust, user-friendly applications:

  • The Error protocol's confusing behavior with localizedDescription
  • Hard-to-understand system error messages
  • Limited type safety in error propagation
  • Difficulties with error chain debugging (relevant for typed throws!)
  • Challenges in collecting meaningful feedback from users

ErrorKit addresses these challenges with a suite of lightweight, interconnected features you can adopt progressively.

Core Features

The Throwable Protocol

Throwable fixes the confusion of Swift's Error protocol by providing a clear, Swift-native approach to error handling:

enum NetworkError: Throwable {
   case noConnectionToServer
   case parsingFailed

   var userFriendlyMessage: String {
      switch self {
      case .noConnectionToServer:
         String(localized: "Unable to connect to the server.")
      case .parsingFailed:
         String(localized: "Data parsing failed.")
      }
   }
}

Now when catching this error, you'll see exactly what you expect:

"Unable to connect to the server."

For rapid development, you can use string raw values:

enum NetworkError: String, Throwable {
   case noConnectionToServer = "Unable to connect to the server."
   case parsingFailed = "Data parsing failed."
}

Read more about Throwable →

Enhanced Error Descriptions

Get improved, user-friendly messages for ANY error, including system errors:

do {
    let _ = try Data(contentsOf: url)
} catch {
    // Better than localizedDescription, works with any error type
    print(ErrorKit.userFriendlyMessage(for: error))
    // "You are not connected to the Internet. Please check your connection."
}

These enhanced descriptions are community-provided and fully localized mappings of common system errors to clearer, more actionable messages.

Read more about Enhanced Error Descriptions →

Swift 6 Typed Throws Support

Swift 6 introduces typed throws (throws(ErrorType)), bringing compile-time type checking to error handling. ErrorKit makes this powerful feature practical with solutions for its biggest challenges:

Error Nesting with Catching

The Catching protocol solves the biggest problem with error handling: nested errors.

enum ProfileError: Throwable, Catching {
    case validationFailed(field: String)
    case caught(Error)  // Single case handles all nested errors!
    
    var userFriendlyMessage: String { /* ... */ }
}

struct ProfileRepository {
    func loadProfile(id: String) throws(ProfileError) -> UserProfile {
        // Regular error throwing for validation
        guard id.isValidFormat else {
            throw ProfileError.validationFailed(field: "id")
        }
        
        // Automatically wrap any database or file errors
        let userData = try ProfileError.catch {
            let user = try database.loadUser(id)
            let settings = try fileSystem.readUserSettings(user.settingsPath)
            return UserProfile(user: user, settings: settings)
        }
        
        return userData
    }
}

Read more about Typed Throws and Error Nesting →

Error Chain Debugging

When using Throwable with the Catching protocol, you get powerful error chain debugging:

do {
    try await updateUserProfile()
} catch {
    Logger().error("\(ErrorKit.errorChainDescription(for: error))")
    
    // Output shows the complete error path:
    // ProfileError
    // └─ DatabaseError
    //    └─ FileError.notFound(path: "/Users/data.db")
    //       └─ userFriendlyMessage: "Could not find database file."
}

Read more about Error Chain Debugging →

Ready-to-Use Tools

Built-in Error Types

Stop reinventing common error types in every project. ErrorKit provides standardized error types for common scenarios:

func fetchUserData() throws(DatabaseError) {
    guard isConnected else {
        throw .connectionFailed
    }
    // Fetching logic
}

Includes ready-to-use types like DatabaseError, NetworkError, FileError, ValidationError, PermissionError, and more – all conforming to both Throwable and Catching with localized messages.

For quick one-off errors, use GenericError:

func quickOperation() throws {
    guard condition else {
        throw GenericError(userFriendlyMessage: "The operation couldn't be completed due to invalid state.")
    }
    // Operation logic
}

Read more about Built-in Error Types →

User Feedback with Error Logs

Gathering diagnostic information from users has never been simpler:

Button("Report a Problem") {
    showMailComposer = true
}
.mailComposer(
    isPresented: $showMailComposer,
    recipient: "support@yourapp.com",
    subject: "Bug Report",
    messageBody: "Please describe what happened:",
    attachments: [
        try? ErrorKit.logAttachment(ofLast: .minutes(30))
    ]
)

With just a simple SwiftUI modifier, you can automatically include all log messages from Apple's unified logging system.

Read more about User Feedback and Logging →

How These Features Work Together

ErrorKit's features are designed to complement each other while remaining independently useful:

  1. Start with improved error definitions using Throwable for custom errors and userFriendlyMessage(for:) for system errors.

  2. Add type safety with Swift 6 typed throws, using the Catching protocol to solve nested error challenges. This pairs with error chain debugging to understand error flows through your app.

  3. Save time with ready-made tools: built-in error types for common scenarios and simple log collection for user feedback.

Adoption Path

Here's a practical adoption strategy:

  1. Replace Error with Throwable in your custom error types
  2. Use ErrorKit.userFriendlyMessage(for:) when showing system errors
  3. Adopt built-in error types where they fit your needs
  4. Implement typed throws with Catching for more robust error flows
  5. Add error chain debugging to improve error visibility
  6. Integrate log collection with your feedback system

Documentation

For complete documentation visit: ErrorKit Documentation

Showcase

I created this library for my own Indie apps (download & rate them to show your appreciation):

App Icon App Name & Description Supported Platforms
TranslateKit: App Localization
AI-powered app localization with unmatched accuracy. Fast & easy: AI & proofreading, 125+ languages, market insights. Budget-friendly, free to try.
Mac
FreemiumKit: In-App Purchases for Indies
Simple In-App Purchases and Subscriptions: Automation, Paywalls, A/B Testing, Live Notifications, PPP, and more.
iPhone, iPad, Mac, Vision
Pleydia Organizer: Movie & Series Renamer
Simple, fast, and smart media management for your Movie, TV Show and Anime collection.
Mac
FreelanceKit: Project Time Tracking
Simple & affordable time tracking with a native experience for all devices. iCloud sync & CSV export included.
iPhone, iPad, Mac, Vision
CrossCraft: Custom Crosswords
Create themed & personalized crosswords. Solve them yourself or share them to challenge others.
iPhone, iPad, Mac, Vision
FocusBeats: Pomodoro + Music
Deep Focus with proven Pomodoro method & select Apple Music playlists & themes. Automatically pauses music during breaks.
iPhone, iPad, Mac, Vision
Posters: Discover Movies at Home
Auto-updating & interactive posters for your home with trailers, showtimes, and links to streaming services.
Vision

About

Simplified error handling with built-in user-friendly messages for common errors. Fully localized. Community-driven.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages