{"id":32150412,"url":"https://github.com/might-fail/swift-might-fail","last_synced_at":"2026-05-27T21:31:38.468Z","repository":{"id":259771783,"uuid":"879368610","full_name":"might-fail/swift-might-fail","owner":"might-fail","description":"A Swift library for handling `async` and `sync` errors without do-catch blocks.","archived":false,"fork":false,"pushed_at":"2025-03-18T01:13:49.000Z","size":43,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-23T01:39:26.804Z","etag":null,"topics":["do-catch","error-as-values","error-handling","might-fail"],"latest_commit_sha":null,"homepage":"https://mightfail.dev/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/might-fail.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-10-27T18:09:43.000Z","updated_at":"2025-06-12T20:16:23.000Z","dependencies_parsed_at":"2025-12-12T02:05:51.187Z","dependency_job_id":null,"html_url":"https://github.com/might-fail/swift-might-fail","commit_stats":null,"previous_names":["might-fail/swift","might-fail/swift-might-fail"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/might-fail/swift-might-fail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/might-fail%2Fswift-might-fail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/might-fail%2Fswift-might-fail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/might-fail%2Fswift-might-fail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/might-fail%2Fswift-might-fail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/might-fail","download_url":"https://codeload.github.com/might-fail/swift-might-fail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/might-fail%2Fswift-might-fail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33585203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["do-catch","error-as-values","error-handling","might-fail"],"created_at":"2025-10-21T10:01:45.167Z","updated_at":"2026-05-27T21:31:38.462Z","avatar_url":"https://github.com/might-fail.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Might Fail\n\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmight-fail%2Fswift-might-fail%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/might-fail/swift-might-fail)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmight-fail%2Fswift-might-fail%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/might-fail/swift-might-fail)\n\n![Build and Test](https://github.com/meech-ward/AsyncCoreBluetooth/actions/workflows/build.yml/badge.svg)\n\n\nA Swift library for handling async and sync errors without `try` and `catch` blocks.\n\n[Documentation](https://swift.mightfail.dev/documentation/mightfail)\n\n## Installation\n\n### Swift Package Manager\n\nAdd MightFail as a dependency to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/might-fail/swift.git\", from: \"0.2.1\")\n]\n```\n\nThen add it to your target's dependencies:\n\n```swift\ntargets: [\n    .target(\n        name: \"YourTarget\",\n        dependencies: [\"MightFail\"]),\n]\n```\n\n### Import\n\nImport MightFail in your source files:\n\n```swift\nimport MightFail\n```\n\n## Usage\n\nMightFail provides a simplified way to handle errors in Swift without traditional try-catch blocks. It works with both synchronous and asynchronous code.\n\n### Important\n\n- **Always** guard the success case.\n- **Never** check the error case.\n\n```swift\n// Good\nguard let data else {\n    // handle error\n}\n// Good\nguard success else {\n    // handle error\n}\n// Bad\nif let error {\n    // handle error\n}\n```\n\n\n### Handling Errors\n\nLike I said, always guard. So the success case is at the bottom of the function.\n\n#### Traditional Error Handling:\n\n```swift\nvar vendingMachine = VendingMachine()\nvendingMachine.coinsDeposited = 8\ndo {\n    try buyFavoriteSnack(person: \"Alice\", vendingMachine: vendingMachine)\n    print(\"Success! Yum.\")\n} catch VendingMachineError.invalidSelection {\n    print(\"Invalid Selection.\")\n} catch VendingMachineError.outOfStock {\n    print(\"Out of Stock.\")\n} catch VendingMachineError.insufficientFunds(let coinsNeeded) {\n    print(\"Insufficient funds. Please insert an additional \\(coinsNeeded) coins.\")\n} catch {\n    print(\"Unexpected error: \\(error).\")\n}\n```\n\n#### With MightFail:\n\n```swift\nlet vendingMachine = VendingMachine()\nvendingMachine.coinsDeposited = 8\nlet (error, _, success) = mightFail {\n    try buyFavoriteSnack(person: \"Alice\", vendingMachine: vendingMachine)\n}\nguard success else {\n    switch error {\n    case VendingMachineError.invalidSelection:\n        print(\"Invalid Selection.\")\n    case VendingMachineError.outOfStock:\n        print(\"Out of Stock.\")\n    case VendingMachineError.insufficientFunds(let coinsNeeded):\n        print(\"Insufficient funds. Please insert an additional \\(coinsNeeded) coins.\")\n    default:\n        print(\"Unexpected error: \\(error).\")\n    }\n    return\n}\nprint(\"Success! Yum.\")\n```\n\n### Basic Synchronous Usage\n\n```swift\n// Returns (error, result, success)\nlet (error, result, success) = mightFail {\n    return \"Success\"\n}\n\n// Check success\nguard success else {\n    print(error)\n    return\n}\n\nprint(result) // \"Success\"\n```\n\n### Simplified Return Type\n\n```swift\n// Returns just (error, result)\nlet (error, result) = mightFail {\n    return 42\n}\n\nguard let result else {\n    print(error) \n    return\n}\n\nprint(result) // 42\n```\n\n\n### Async Support\n\n```swift\n// Basic async usage\nlet (error, result, success) = await mightFail {\n    try await Task.sleep(nanoseconds: 1_000_000)\n    return \"Async Success\"\n}\n\n// Simplified async return\nlet (error, result) = await mightFail {\n    try await Task.sleep(nanoseconds: 1_000_000)\n    return 42\n}\n```\n\n### Multiple Operations\n\nYou can run multiple operations and get their results:\n\n```swift\nlet results = mightFail([\n    { 1 },\n    { throw TestError.simple },\n    { 3 },\n])\n\n// Check results\nresults.forEach { (error, result) in\n    guard let result else {\n        print(\"Error: \\(error)\")\n        return\n    }\n    print(\"Result: \\(result)\")\n}\n```\n\nOr maybe something like this:\n\n```swift\nguard let imageFiles = await memoryStorage.imageFilesStore[imageId] else {\n    return\n}\nlet deleteResults = mightFail([\n    { try FileStorage.deleteFile(name: imageFiles.fullSizeName, ext: imageFiles.ext) },\n    { try FileStorage.deleteFile(name: imageFiles.thumbnailName, ext: imageFiles.ext) },\n    { try FileStorage.deleteFile(name: imageFiles.mediumSizeName, ext: imageFiles.ext) },\n])\n\nfor deleteResult in deleteResults.filter({ $0.success == false }) {\n    print(\"Failed to delete image file: \\(deleteResult.error)\")\n}\n\nfor deleteResult in deleteResults.filter({ $0.success == true }) {\n    print(\"Deleted image file: \\(deleteResult.result)\")\n}\n```\n\n### Optional Values\n\nIf you pass an optional value to mightFail, the first guard is for the error check, you'll need a second guard to see if you have a value.\n\n```swift\nfunc returnOptional() throws -\u003e String? {\n    return nil\n}\n\nlet (error, result) = mightFail {\n    try returnOptional()\n}\n\n// result is String??\nguard let result else {\n    // there was an error, handle it \n    print(error)\n    return\n}\n\nguard let result else {\n   // no error, but result is nil, handle it \n   print(\"No result\")\n   return\n}\n\nprint(result) // \"Success\"\n```\n\n---\n\n# do, try, catch is bad\n\nI think throwing exceptions is nice, I like that an exception breaks control flow and I like exception propogation. The only thing I don't like catching exceptions.\n\nThis mostly happens at the most \"user facing\" part of the code like an api endpoint or a UI component, the outer most function call. So catching an exception needs to notify the user that something went wrong, log the error for debugging, and stop the currently execution flow.\n\n## Guard ✅\n\nGuarding allows you to handle your errors early and return from the function early, making them more readable and easier to reason about.\n\n```swift\n// Generic fetch function that can work with any Codable type\nfunc fetch\u003cT: Codable\u003e(from urlString: String) async throws -\u003e Data {\n    guard let url = URL(string: urlString) else {\n        throw URLError(.badURL)\n    }\n\n    // Create and configure the URL session\n    let session = URLSession.shared\n\n    // Make the network request and await the response\n    let (data, response) = try await session.data(from: url)\n\n    guard let data = data else {\n        throw URLError(.badServerResponse)\n    }\n\n    // Verify we got a successful HTTP response\n    guard let httpResponse = response as? HTTPURLResponse,\n            (200...299).contains(httpResponse.statusCode) else {\n        throw URLError(.badServerResponse)\n    }\n}\n```\n\nThe success case is now the only code that is not nested in an `if` or `guard` statement. It's also at the very bottom of the function making it easy to find.\n\nBut for some reason, when we invoke this function, we think it's fine to just throw away all the benefits of the guard statement.\n\n```swift\ndo {\n    let data = try await networkManager.fetch(\n        from: \"https://jsonplaceholder.typicode.com/posts/1\"\n    )\n    // success case in the middle somewhere and nested\n} catch {\n    print(\"Error fetching post: \\(error)\")\n}\n```\n\n## Everything in One Do/Try/Catch Block ❌\n\nThen this leads to putting a whole bunch of code in the `do` block.\n\n```swift\ntry {\n    let data = try await networkManager.fetch(\n        from: \"https://jsonplaceholder.typicode.com/posts/1\"\n    )\n\n    // Decode the JSON data into our Codable type\n    let decoder = JSONDecoder()\n    let post = try decoder.decode(Post.self, from: data)\n\n    try post.data.write(toFile: \"path/to/newfile.txt\", atomically: true, encoding: .utf8)\n\n    print(\"Successfully fetched, decoded, and saved the post\")\n} catch (error) {\n  // handle any errors, not sure which one though 🤷‍♀️\n}\n\n// or\n\ncatch let error as URLError {\n    print(\"Network error: \\(error.localizedDescription)\")\n\n} catch let error as DecodingError {\n    print(\"JSON error: \\(error.localizedDescription)\")\n\n} catch let error as CocoaError {\n    print(\"File error: \\(error.localizedDescription)\")\n\n} catch {\n    print(\"Unexpected error: \\(error)\")\n}\n```\n\nThis is bad because:\n\n1. All the success case code will happen inside of the do block. Nested somewhere in the middle of the function.\n2. We handle the errors away from the code that causes the error and a sense of order is lost.\n\n## Multiple Do/Try/Catch Blocks ❌\n\n```ts\n// First try-catch for network request\nlet data: Data\ndo {\n    data = try await networkManager.fetch(\n        from: \"https://jsonplaceholder.typicode.com/posts/1\"\n    )\n} catch let error as URLError {\n    print(\"Network error: \\(error.localizedDescription)\")\n    return // or throw, or handle error differently\n} catch {\n    print(\"Unexpected network error: \\(error)\")\n    return\n}\n\n// Second try-catch for JSON decoding\nlet post: Post\ndo {\n    let decoder = JSONDecoder()\n    post = try decoder.decode(Post.self, from: data)\n} catch let error as DecodingError {\n    print(\"JSON decoding error: \\(error.localizedDescription)\")\n    return\n} catch {\n    print(\"Unexpected decoding error: \\(error)\")\n    return\n}\n\n// Third try-catch for file writing\ndo {\n    try post.data.write(toFile: \"path/to/newfile.txt\", atomically: true, encoding: .utf8)\n} catch let error as CocoaError {\n    print(\"File writing error: \\(error.localizedDescription)\")\n    return\n} catch {\n    print(\"Unexpected file error: \\(error)\")\n    return\n}\n\n// If we get here, everything succeeded\nprint(\"Successfully fetched, decoded, and saved the post\")\n```\n\nThis might be a better way to handle errors, but no one's going to write three do catch blocks like this. And a catch isn't as good as a guard because it doesn't force you to handle the error and return early.\n\n## The correct way\n\nGuarding is good, and error handling should be handled in a guard right next to the code that causes the error. Success case code should go after guarding for errors.\n\nWe already know this, now let's do this with code that throws.\n\n```swift\n// First try-catch for network request\nlet (networkError, data) = await mightFail { try await networkManager.fetch(\n    from: \"https://jsonplaceholder.typicode.com/posts/1\")\n}\nguard let data else {\n    switch networkError {\n    case URLError.badURL:\n        print(\"Bad URL\")\n    default:\n        print(\"Network error: \\(networkError)\")\n    }\n    return // or throw, or handle error differently\n}\n\n// Second try-catch for JSON decoding\nlet decoder = JSONDecoder()\nlet (decodingError, post) = await mightFail {\n    try decoder.decode(Post.self, from: data)\n}\nguard let post else {\n    switch decodingError {\n    case DecodingError.keyNotFound:\n        print(\"Key not found\")\n    default:\n        print(\"Decoding error: \\(decodingError)\")\n    }\n    return\n}\n\n// Third try-catch for file writing\nlet (fileError, _, success) = await mightFail {\n    try post.data.write(toFile: \"path/to/newfile.txt\", atomically: true, encoding: .utf8)\n}\nguard success else {\n    switch fileError {\n    case CocoaError.fileWriteNoPermission:\n        print(\"No permission to write file\")\n    default:\n        print(\"File writing error: \\(fileError)\")\n    }\n    return\n}\n\n// If we get here, everything succeeded\nprint(\"Successfully fetched, decoded, and saved the post\")\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmight-fail%2Fswift-might-fail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmight-fail%2Fswift-might-fail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmight-fail%2Fswift-might-fail/lists"}