# Error Handling Patterns and Application Error Codes in apple/container: A Complete Guide

> Master apple/container error handling. Explore Swift enum errors, AppError, and POSIX bridging for robust applications. Learn common patterns and error codes.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: best-practices
- Published: 2026-06-24

---

**The apple/container repository implements a layered Swift error handling strategy that combines domain-specific enum errors, a protocol-based `AppError` system with stable string codes, and POSIX error bridging for system-level operations.**

Understanding how the apple/container project manages failures is essential for contributing to or extending this containerization framework. The codebase adopts idiomatic Swift error handling patterns while providing structured application error codes that enable programmatic error classification. This guide examines the implementation details, key source files, and practical usage patterns found throughout the repository.

## Swift Enum-Based Error Patterns

The foundation of error handling in apple/container relies on **local Swift enum errors** that conform to `Swift.Error` and `CustomStringConvertible`. Each module defines its own error enum to capture validation failures and unexpected states specific to that domain.

### Local Error Definitions in ProgressConfig.swift

In [`ProgressConfig.swift`](https://github.com/apple/container/blob/main/ProgressConfig.swift), errors are defined as a simple enum with associated values for detailed failure reasons:

```swift
public enum Error: Swift.Error, CustomStringConvertible {
    case invalid(String)

    public var description: String {
        switch self {
        case .invalid(let reason):
            return "failed to validate config (\(reason))"
        }
    }
}

```

This pattern provides human-readable descriptions through the `description` property, which the codebase uses for logging and user-visible messages without exposing raw error objects.

### Builder.swift Error Types

The [`Builder.swift`](https://github.com/apple/container/blob/main/Builder.swift) file defines a more comprehensive error enum that handles various build-time failures:

```swift
public enum Error: Swift.Error, CustomStringConvertible {
    case invalidContinuation
    case buildComplete
    case invalidExport(String, String)
}

```

These cases capture specific failure modes such as invoking operations after build completion or validating export entries. The `invalidExport` case includes two associated strings to identify the problematic entry and the specific validation failure reason.

### Plugin and Build Service Errors

Other modules follow the same structural pattern. [`PluginsService.swift`](https://github.com/apple/container/blob/main/PluginsService.swift) defines errors like `pluginNotFound` and `conflict`, while [`BuildStdio.swift`](https://github.com/apple/container/blob/main/BuildStdio.swift) and [`BuildRemoteContentProxy.swift`](https://github.com/apple/container/blob/main/BuildRemoteContentProxy.swift) expose domain-specific cases that map directly to their respective failure points. This modular approach keeps error definitions close to their usage contexts while maintaining consistency across the codebase.

## Structured Application Errors with AppError Protocol

For errors requiring programmatic classification, apple/container implements a **structured error protocol** that couples exceptions with stable, machine-readable codes.

### The AppError Protocol Definition

Defined in [`ApplicationError.swift`](https://github.com/apple/container/blob/main/ApplicationError.swift), the `AppError` protocol establishes a contract for errors that need metadata and stable identifiers:

```swift
public protocol AppError: Error {
    var code: AppErrorCode { get }
    var metadata: OrderedDictionary<String, String> { get }
    var underlyingError: Error? { get }
}

```

Concrete implementations like `ResourceLabels.LabelError` provide these properties, allowing callers to inspect `code` to determine appropriate recovery actions—such as rejecting invalid user input versus handling system bugs differently.

### AppErrorCode Implementation

The `AppErrorCode` struct provides lightweight, string-based error classification:

```swift
public struct AppErrorCode: RawRepresentable, Hashable, Sendable {
    public let rawValue: String
    public init(rawValue: String) { self.rawValue = rawValue }
}

```

Common codes defined in [`ApplicationError.swift`](https://github.com/apple/container/blob/main/ApplicationError.swift) and extended in [`ResourceLabels.swift`](https://github.com/apple/container/blob/main/ResourceLabels.swift) include:

- `invalid_argument` for generic caller errors such as bad CLI flags
- `invalid_label_key_content` for label keys containing illegal characters
- `invalid_label_key_length` for keys exceeding 128 bytes
- `invalid_label_length` for entire `key=value` pairs exceeding 4096 bytes

The extension in [`ResourceLabels.swift`](https://github.com/apple/container/blob/main/ResourceLabels.swift) adds these label-specific codes as static properties:

```swift
extension AppErrorCode {
    public static let invalidLabelKeyContent = AppErrorCode(rawValue: "invalid_label_key_content")
    public static let invalidLabelKeyLength = AppErrorCode(rawValue: "invalid_label_key_length")
    public static let invalidLabelLength = AppErrorCode(rawValue: "invalid_label_length")
}

```

### Resource Label Validation Example

When validating resource labels, the codebase uses the `AppError` protocol to provide detailed failure context:

```swift
do {
    let labels = try ResourceLabels(["com.example.key": "value"])
    // labels are safe to use
} catch let err as ResourceLabels.LabelError {
    print("Label error: \(err.code.rawValue) – \(err.metadata)")
}

```

This pattern enables precise error handling based on specific validation failures while maintaining type safety.

## POSIX Error Bridging for System Calls

Low-level system operations in apple/container require **POSIX error bridging** to convert C library failures into Swift errors.

### Converting errno to Swift Errors

In [`Builder.swift`](https://github.com/apple/container/blob/main/Builder.swift), socket configuration functions demonstrate the bridging pattern:

```swift
private func setSockOpt(level: Int32, name: Int32, value: Int) throws {
    // ... socket setup code ...
    if res == -1 {
        throw POSIXError(POSIXErrorCode(rawValue: errno) ?? .EPERM)
    }
}

```

Higher-level callers catch `POSIXError` and often convert these system errors into domain-specific Swift errors. This creates a tidy boundary between system calls and the Swift-level error handling model, ensuring that components like `FileHandle` extensions propagate meaningful errors without leaking implementation details.

## Error Propagation and Consumption Patterns

Functions that can fail are explicitly marked with `throws`, following idiomatic Swift conventions. The `build` method in [`Builder.swift`](https://github.com/apple/container/blob/main/Builder.swift) demonstrates this pattern:

```swift
public func build(_ config: BuildConfig) async throws {
    guard let continuation else {
        throw Error.invalidContinuation
    }
    // ... additional validation ...
    try await self.client.performBuild(...)
}

```

Consumers use `try await` within `Task` or `async` contexts, allowing errors to bubble up to CLI entry points where they convert into user-visible messages or exit codes. This propagation model ensures that validation errors from [`ProgressConfig.swift`](https://github.com/apple/container/blob/main/ProgressConfig.swift), label errors from [`ResourceLabels.swift`](https://github.com/apple/container/blob/main/ResourceLabels.swift), and build errors from [`Builder.swift`](https://github.com/apple/container/blob/main/Builder.swift) all surface consistently at the application boundary.

## Summary

The apple/container repository implements a consistent, multi-layered error handling architecture:

- **Domain-specific enum errors** provide type-safe failure representation with human-readable descriptions via `CustomStringConvertible`
- **The `AppError` protocol** enables structured error classification using stable `AppErrorCode` strings for programmatic error handling
- **POSIX error bridging** cleanly wraps system-level failures into the Swift error model
- **Explicit `throws` declarations** maintain clear error propagation paths from low-level operations through to CLI interfaces

## Frequently Asked Questions

### What is the difference between local enum errors and AppError in apple/container?

Local enum errors defined in files like [`ProgressConfig.swift`](https://github.com/apple/container/blob/main/ProgressConfig.swift) and [`Builder.swift`](https://github.com/apple/container/blob/main/Builder.swift) provide module-specific validation failures with human-readable descriptions. The `AppError` protocol, defined in [`ApplicationError.swift`](https://github.com/apple/container/blob/main/ApplicationError.swift), adds machine-readable error codes and structured metadata for errors that require programmatic handling, such as label validation failures in [`ResourceLabels.swift`](https://github.com/apple/container/blob/main/ResourceLabels.swift).

### How does apple/container handle system-level POSIX errors?

The codebase converts POSIX errors to Swift errors using `POSIXError` and `POSIXErrorCode`. In [`Builder.swift`](https://github.com/apple/container/blob/main/Builder.swift), low-level socket operations check `errno` and throw `POSIXError` when system calls return -1. Higher-level components typically catch these and convert them to domain-specific errors, maintaining separation between system interfaces and application logic.

### Where are application error codes defined in the repository?

Application error codes are defined in [`ApplicationError.swift`](https://github.com/apple/container/blob/main/ApplicationError.swift) as static properties on the `AppErrorCode` struct. Common codes like `invalid_argument` reside there, while module-specific extensions like those in [`ResourceLabels.swift`](https://github.com/apple/container/blob/main/ResourceLabels.swift) add specialized codes such as `invalid_label_key_content` and `invalid_label_length`.

### How should I handle errors when calling the build API in apple/container?

When calling `builder.build(_ config: BuildConfig)`, use `try await` within a `do-catch` block. Catch specific `Builder.Error` cases like `invalidExport` to handle validation failures, or catch the general `AppError` protocol to inspect error codes programmatically. All build-related errors propagate through the `async throws` interface, allowing you to handle them at the appropriate abstraction level.