Design or repair Swift error handling style using throws, typed throws, Result, Optional, AsyncSequence failure types, domain errors, Cocoa bridging, and concise functional recovery paths.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add gaelic-ghost/socket --skill swift-error-handling-style-workflow --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Swift Error Handling Style Workflow?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/gaelic-ghost-swift-error-handling-style-workflow)More formats (shields.io, HTML) on the badges page.
---
name: swift-error-handling-style-workflow
description: Design or repair Swift error handling style using throws, typed throws, Result, Optional, AsyncSequence failure types, domain errors, Cocoa bridging, and concise functional recovery paths.
license: Apache-2.0
metadata:
owner: gaelic-ghost
repo: socket
category: swift-language
---
# Swift Error Handling Style Workflow
## Purpose
Make Swift failure behavior clear at the call site and useful when something
breaks.
The house style is concise, typed by default for Swift-owned failure surfaces,
and functional in feel: fallible values should move through explicit carriers,
error messages should explain the failed operation, and recovery should happen
at the boundary that can actually choose a next step.
## Source Check
Use repo-local guidance first. For general language behavior, prefer the Swift
Book, Swift Standard Library docs, Swift Evolution, and Apple Foundation docs:
- [Error Handling in The Swift Programming Language](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/errorhandling/)
- [SE-0413: Typed throws](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0413-typed-throws.md)
- [Result](https://developer.apple.com/documentation/swift/result)
- [About Imported Cocoa Error Parameters](https://developer.apple.com/documentation/swift/about-imported-cocoa-error-parameters)
- [Handling Cocoa Errors in Swift](https://developer.apple.com/documentation/swift/handling-cocoa-errors-in-swift)
- [LocalizedError](https://developer.apple.com/documentation/foundation/localizederror)
- [CustomNSError](https://developer.apple.com/documentation/foundation/customnserror)
- [RecoverableError](https://developer.apple.com/documentation/foundation/recoverableerror)
## When To Use
- Use this skill when designing or reviewing Swift error surfaces.
- Use this skill when code hides recoverable failures in `nil`, strings, logs, or
broad catch-all wrappers.
- Use this skill when deciding between `throws`, typed throws, `Result`,
`Optional`, `AsyncSequence` failure types, framework errors, or domain errors.
- Use this skill when modernizing nested `do`/`catch`, callback-era
`Result`-passing, weak diagnostics, or awkward Objective-C/Cocoa error
bridging.
## Workflow
1. Identify the failure boundary:
- operation
- inputs
- success value
- expected absence
- recoverable failures
- programmer errors
- framework or transport errors
- async or streaming boundary
2. Choose the carrier:
- nonoptional value when failure is impossible after construction
- `Optional` when absence is expected and not diagnostic
- typed throws for Swift-owned fallible operations when the error type can be
named clearly
- untyped `throws` or `async throws` when the operation forwards broad,
open-ended framework, filesystem, networking, database, plugin, or
dependency failures without adding a useful typed boundary
- `Result` when success or failure must be stored, combined, cached, tested,
or delivered through a non-throwing callback
- `AsyncSequence` failure types when values arrive over time and iteration can
fail
- existing framework errors when the platform already gives a precise error
domain
3. Model domain failures:
- prefer existing framework errors until a concrete custom domain, extension,
or call-site recovery need appears
- prefer small `enum` errors with associated values when the cases are closed
and meaningful
- preserve underlying errors when they help diagnosis
- use `LocalizedError` for user-visible or operator-facing descriptions
- use `CustomNSError` when Cocoa interop, error domains, codes, or user-info
keys matter
- use `RecoverableError` only when the caller can present concrete recovery
choices
4. Keep flow concise:
- use `try` and `try await` for straight-line fallible work
- use `map`, `flatMap`, `mapError`, `Result.get()`, and typed transforms when
the failure value is intentionally part of the pipeline
- prefer functional composition over imperative branching whenever it stays
accurate and readable
- split long chains at diagnostic, side-effect, actor, or async boundaries
- catch narrowly where recovery happens
- let errors propagate when the current layer has no useful recovery decision
5. Improve diagnostics:
- include operation, source, important input identity, likely cause, and next
inspection point when the error reaches a human
- keep low-level details available without dumping secrets or raw payloads
- log at the boundary that has context, not at every propagation hop
- avoid vague messages such as `failed`, `invalid`, or `unknown error`
## House Defaults
- Prefer typed throws for Swift-owned synchronous and structured-concurrency
APIs when the error type can be named clearly.
- Prefer untyped `throws` when forwarding broad framework, filesystem,
networking, database, plugin, or dependency failures without changing their
meaning.
- Prefer `Result` for value-level composition, storage, callback interop, batch
outcomes, and tests that need to assert failure as data.
- Prefer `Optional` only for ordinary absence. Do not erase useful failure
information to make a pipeline look tidy.
- Prefer existing Foundation, Cocoa, SwiftPM, SwiftNIO, Vapor, Hummingbird, or
framework error types until a concrete custom domain, extension, or recovery
need appears.
- Prefer small domain error enums over broad wrapper hierarchies when custom
errors are needed.
- Prefer preserving underlying errors over stringifying them.
- Prefer direct propagation over local catch-and-rethrow wrappers that add no new
context.
- Prefer functional transforms, narrow recovery helpers, and value-level error
composition over broad imperative branching.
- Prefer assertions, preconditions, or non-throwing validation for programmer
mistakes only when recovery is not part of the API contract.
## Typed Throws Guidance
Typed throws is the preferred house style for Swift-owned error surfaces, while
untyped `throws` remains the right tool for open-ended failure domains.
Use typed throws when:
- the operation has a closed domain error set
- the operation is Swift-owned and the error type can be named clearly
- callers benefit from exhaustive `catch` handling
- tests should assert every domain case
- a generic API should preserve its caller's failure type
- embedded, performance-sensitive, or allocation-sensitive code benefits from
carrying a concrete error type
Avoid typed throws when:
- the operation mostly forwards framework, filesystem, networking, database, or
plugin errors without adding a meaningful typed boundary
- the API boundary is public and the error set is likely to grow
- callers would immediately erase the type to `any Error`
- the type annotation makes simple code noisier without changing recovery
## Error Helper Direction
A small shared helper package could become useful if several repositories start
needing the same concise diagnostic, wrapping, or recovery helpers.
Treat that as a separate design decision. A future package might explore generic
helpers, variadic generics or parameter packs, and macros, but do not invent a
local helper framework inside one app or skill unless the repeated call sites
already exist and the package design has been discussed.
Use the root Socket maintainer plan at
`docs/maintainers/errorhandles-package-plan.md` when deciding whether that helper
belongs in Socket or in a separate Swift package repository.
## Example Shapes
Straight-line fallible work:
```swift
func loadManifest(at url: URL) async throws -> Manifest {
let data = try await fetch(url)
return try ManifestDecoder().decode(data)
}
```
Closed domain failures:
```swift
enum ManifestError: Error, Equatable {
case missingName(URL)
case unsupportedVersion(String)
}
func validate(_ manifest: Manifest) throws(ManifestError) -> Manifest {
guard let name = manifest.name else {
throw .missingName(manifest.sourceURL)
}
guard manifest.version.isSupported else {
throw .unsupportedVersion(manifest.version.rawValue)
}
return manifest
}
```
Stored or batched failures:
```swift
let results: [Result<Package, PackageLoadError>] = urls.map { url in
Result { try loadPackage(at: url) }
}
let packages = results.compactMap { try? $0.get() }
let failures = results.compactMap { result -> PackageLoadError? in
guard case let .failure(error) = result else { return nil }
return error
}
```
Operator-facing error context:
```swift
enum PackageLoadError: LocalizedError {
case unreadableManifest(url: URL, underlying: any Error)
var errorDescription: String? {
switch self {
case let .unreadableManifest(url, underlying):
"Could not read Package.swift at \(url.path). Check that the file exists, is readable, and contains valid Swift package syntax. Underlying error: \(underlying)"
}
}
}
```
## Output Shape
Return:
1. `Failure state`: current operation, success value, absence, recoverable
failures, and programmer errors.
2. `Carrier choice`: why `throws`, typed throws, `Result`, `Optional`,
`AsyncSequence`, existing framework errors, or domain errors fit.
3. `House-style changes`: API signatures, error types, propagation, recovery,
and diagnostics to change.
4. `Examples`: compact call-site or implementation sketch.
5. `Validation`: compile, tests, and failure-case checks needed.
## Guardrails
- Do not add error abstraction layers without a real caller, recovery path, or
interop need.
- Do not wrap every underlying error just to make a local enum exhaustive.
- Do not force typed throws onto APIs whose failures are still genuinely
open-ended.
- Do not hide recoverable failures in logs, `nil`, default values, or comments.
- Do not over-functionalize error handling when a narrow `do`/`catch` is clearer.
- Do not catch only to print or log and then continue with corrupted state.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!