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
Errorprotocol's confusing behavior withlocalizedDescription - 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." }
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." // String interpolation automatically uses userFriendlyMessage(for:) print("Request failed: \(error)") }
These enhanced descriptions are community-provided and fully localized mappings of common system errors to clearer, more actionable messages. ErrorKit comes with built-in mappers for Foundation, CoreData, MapKit, and more. You can also create custom mappers for third-party libraries or your own error types.
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 { print(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 built-in SwiftUI modifier and the logAttachment helper function, you can easily include all log messages from Apple's unified logging system and let your users send them to you via email. Other integrations are also supported.
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:
-
Start with improved error definitions using
Throwablefor custom errors anduserFriendlyMessage(for:)for system errors. -
Add type safety with Swift 6 typed throws, using the
Catchingprotocol to solve nested error challenges. This pairs with error chain debugging to understand error flows through your app. -
Save time with ready-made tools: built-in error types for common scenarios and simple log collection for user feedback.
-
Extend with custom mappers: Create error mappers for any library to improve error messages across your entire application.
Adoption Path
Here's a practical adoption strategy:
- Replace
ErrorwithThrowablein your custom error types - Use
ErrorKit.userFriendlyMessage(for:)when showing system errors - Adopt built-in error types where they fit your needs
- Implement typed throws with
Catchingfor more robust error flows - Add error chain debugging to improve error visibility
- 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 |
