From swift-lang
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.
How this skill is triggered — by the user, by Claude, or both
Slash command
/swift-lang:swift-error-handling-style-workflowThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Make Swift failure behavior clear at the call site and useful when something
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.
Use repo-local guidance first. For general language behavior, prefer the Swift Book, Swift Standard Library docs, Swift Evolution, and Apple Foundation docs:
nil, strings, logs, or
broad catch-all wrappers.throws, typed throws, Result,
Optional, AsyncSequence failure types, framework errors, or domain errors.do/catch, callback-era
Result-passing, weak diagnostics, or awkward Objective-C/Cocoa error
bridging.Optional when absence is expected and not diagnosticthrows or async throws when the operation forwards broad,
open-ended framework, filesystem, networking, database, plugin, or
dependency failures without adding a useful typed boundaryResult when success or failure must be stored, combined, cached, tested,
or delivered through a non-throwing callbackAsyncSequence failure types when values arrive over time and iteration can
failenum errors with associated values when the cases are closed
and meaningfulLocalizedError for user-visible or operator-facing descriptionsCustomNSError when Cocoa interop, error domains, codes, or user-info
keys matterRecoverableError only when the caller can present concrete recovery
choicestry and try await for straight-line fallible workmap, flatMap, mapError, Result.get(), and typed transforms when
the failure value is intentionally part of the pipelinefailed, invalid, or unknown errorthrows when forwarding broad framework, filesystem,
networking, database, plugin, or dependency failures without changing their
meaning.Result for value-level composition, storage, callback interop, batch
outcomes, and tests that need to assert failure as data.Optional only for ordinary absence. Do not erase useful failure
information to make a pipeline look tidy.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:
catch handlingAvoid typed throws when:
any ErrorA 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.
Straight-line fallible work:
func loadManifest(at url: URL) async throws -> Manifest {
let data = try await fetch(url)
return try ManifestDecoder().decode(data)
}
Closed domain failures:
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:
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:
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)"
}
}
}
Return:
Failure state: current operation, success value, absence, recoverable
failures, and programmer errors.Carrier choice: why throws, typed throws, Result, Optional,
AsyncSequence, existing framework errors, or domain errors fit.House-style changes: API signatures, error types, propagation, recovery,
and diagnostics to change.Examples: compact call-site or implementation sketch.Validation: compile, tests, and failure-case checks needed.nil, default values, or comments.do/catch is clearer.npx claudepluginhub gaelic-ghost/socket --plugin swift-langCreates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.