# Error Handling in Apple/Container: A Swift-Native Architecture Guide

> Discover how Apple/Container implements type-safe error handling with Swift's Error protocol and domain-specific enums for clear diagnostics and compile-time safety. Learn more.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: architecture
- Published: 2026-06-27

---

**Apple/Container implements a type-safe error handling strategy using Swift's Error protocol with domain-specific enums conforming to CustomStringConvertible, enabling clear diagnostics and compile-time safety across modules like ProgressConfig, PluginsService, and the DNS subsystem.**

Error handling in apple/container follows Swift idiomatic patterns that prioritize type safety and clear diagnostics. The repository defines domain-specific error enums for each subsystem—from progress rendering to DNS resolution—ensuring that failures are captured at compile time and surfaced with human-readable descriptions. This architecture makes debugging container runtime issues predictable across the codebase.

## Domain-Specific Error Types

Apple/Container isolates failure domains by defining typed enums for each component. This approach prevents error collisions and makes failure modes self-documenting.

### ProgressConfig.Error in ProgressConfig.swift

The progress rendering system defines its own error type for validation failures. In [`ProgressConfig.swift`](https://github.com/apple/container/blob/main/ProgressConfig.swift), the enum conforms to both `Swift.Error` and `CustomStringConvertible`:

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

```

This error is thrown during initialization when parameters fail validation. For example, if `totalTasks` is zero or negative, the `init` method throws `ProgressConfig.Error.invalid` with a descriptive message. See the validation logic in lines 21-34 of [`ProgressConfig.swift`](https://github.com/apple/container/blob/main/ProgressConfig.swift).

### PluginsService.Error in PluginsService.swift

The plugin management layer defines `PluginsService.Error` to handle lookup and loading failures:

```swift
public enum Error: Swift.Error, CustomStringConvertible { 
    case pluginNotFound(String)
    case pluginNotLoaded(String) 
}

```

When `PluginsService.load(name:)` cannot locate a plugin binary or fails to load it, it propagates these specific cases. The service translates internal failures into descriptive strings like "plugin not found: \(name)" at lines 99-108 of [`PluginsService.swift`](https://github.com/apple/container/blob/main/PluginsService.swift).

### DNS Subsystem Errors

The DNS server uses separate error types for resolution and binding operations. `DNSResolverError` (defined in [`Types.swift`](https://github.com/apple/container/blob/main/Types.swift)) and `DNSBindError` (defined in [`DNSBindError.swift`](https://github.com/apple/container/blob/main/DNSBindError.swift)) both conform to `CustomStringConvertible` and carry descriptions that mirror DNS RFC error codes. These enums capture specific failure modes like invalid queries or record binding failures.

### ContainerizationError in RuntimeService.swift

For container runtime operations, the codebase imports `ContainerizationError` from the external `Containerization` package. This error type provides structured failure information including a `code` (e.g., `.invalidArgument`, `.notFound`) and a detailed `message`. [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) uses this extensively at lines 149, 201, and 390 to flag invalid states, missing resources, or argument errors when manipulating container runtime state.

### Supporting Error Types

Additional domain-specific errors include:

- **CommandError** (defined in [`CommandResult.swift`](https://github.com/apple/container/blob/main/CommandResult.swift)): A test-only enum capturing subprocess failures with cases like `executionFailed(String)` and `nonZeroExit(Int, String)`.
- **FileLogHandler.FileLogFailure** (defined in [`FileLogHandler.swift`](https://github.com/apple/container/blob/main/FileLogHandler.swift)): Handles logging subsystem failures with cases for `openFailed` and `writeFailed`.

## Common Error Handling Patterns

Apple/Container follows consistent patterns that make error handling predictable and maintainable.

**Typed enums per domain.** Each logical area owns its error type, preventing cross-contamination between unrelated subsystems.

**CustomStringConvertible conformance.** Most errors implement a `description` property providing concise diagnostics without requiring separate localization tables.

**Guard-based validation.** Constructors validate arguments early and throw domain-specific errors immediately when preconditions fail. This fail-fast approach appears in `ProgressConfig.init` and similar validation-heavy initializers.

**Error propagation.** Higher-level APIs like `PluginsService` and `RuntimeService` catch lower-level errors, wrap them if necessary, and re-throw more user-focused enums that preserve context while simplifying caller handling.

**Testing with `#expect(throws:)`**. The test suite verifies that public APIs throw expected error types, ensuring contracts remain stable across refactors.

## Practical Code Examples

### Validating ProgressConfig Initialization

When creating a `ProgressConfig` with invalid parameters, catch the specific error type:

```swift
do {
    let cfg = try ProgressConfig(totalTasks: 0)   // invalid: tasks must be > 0
    // use cfg …
} catch let err as ProgressConfig.Error {
    print("Progress config failed:", err)          // "failed to validate config (totalTasks must be greater than zero)"
}

```

*Source:* [`ProgressConfig.swift`](https://github.com/apple/container/blob/main/ProgressConfig.swift) (lines 21-34).

### Handling Plugin Loading Failures

Use pattern matching to distinguish between missing plugins and load failures:

```swift
let service = PluginsService(pluginLoader: loader, log: logger)

do {
    try service.load(name: "my-plugin")
} catch PluginsService.Error.pluginNotFound(let name) {
    print("❌ No such plugin:", name)
} catch {
    print("⚠️ Unexpected error:", error)
}

```

*Source:* [`PluginsService.swift`](https://github.com/apple/container/blob/main/PluginsService.swift) (error enum at lines 99-108).

### Catching DNS Resolution Errors

The DNS resolver exposes specific error cases for invalid queries:

```swift
do {
    let answer = try dnsResolver.resolve("example.invalid")
} catch DNSResolverError.invalidQuery(let reason) {
    print("Bad DNS query:", reason)
}

```

*Source:* [`Types.swift`](https://github.com/apple/container/blob/main/Types.swift) (DNSResolverError definition).

### Handling Container Runtime Failures

Runtime operations use the external `ContainerizationError` type:

```swift
do {
    try runtime.start(containerID: "abc123")
} catch let err as ContainerizationError {
    print("Container start failed – code:", err.code, "msg:", err.message)
}

```

*Source:* [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) (extensive usage at lines 149, 201, 390).

## Key Implementation Files

| File | Error Type | Purpose |
|------|------------|---------|
| [`ProgressConfig.swift`](https://github.com/apple/container/blob/main/ProgressConfig.swift) | `ProgressConfig.Error` | Validation of progress rendering configuration |
| [`PluginsService.swift`](https://github.com/apple/container/blob/main/PluginsService.swift) | `PluginsService.Error` | Plugin lookup and loading failures |
| [`Types.swift`](https://github.com/apple/container/blob/main/Types.swift) | `DNSResolverError` | DNS query resolution errors |
| [`DNSBindError.swift`](https://github.com/apple/container/blob/main/DNSBindError.swift) | `DNSBindError` | DNS record binding failures |
| [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) | `ContainerizationError` | Container runtime state manipulation |
| [`CommandResult.swift`](https://github.com/apple/container/blob/main/CommandResult.swift) | `CommandError` | Test harness subprocess execution |
| [`FileLogHandler.swift`](https://github.com/apple/container/blob/main/FileLogHandler.swift) | `FileLogHandler.FileLogFailure` | Log file I/O operations |

## Summary

- **Domain isolation:** Each subsystem defines its own error enum (e.g., `ProgressConfig.Error`, `PluginsService.Error`) preventing type collisions.
- **Human-readable diagnostics:** Errors conform to `CustomStringConvertible` to provide immediate context without localization overhead.
- **Fail-fast validation:** Initializers use guard-based validation to throw errors immediately when preconditions fail.
- **Type-safe propagation:** Higher-level services catch and re-throw errors with appropriate context, maintaining Swift's type safety throughout the call stack.
- **Comprehensive test coverage:** The suite uses `#expect(throws:)` to verify error contracts remain stable.

## Frequently Asked Questions

### How does apple/container handle validation errors in configuration objects?

Configuration objects like `ProgressConfig` validate parameters during initialization and throw domain-specific errors immediately. For example, `ProgressConfig.init` throws `ProgressConfig.Error.invalid` when `totalTasks` is zero or negative, catching invalid states before they propagate to rendering logic.

### What distinguishes ContainerizationError from other error types in the codebase?

`ContainerizationError` is an external dependency from the `Containerization` package used primarily in [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift), while domain-specific errors like `ProgressConfig.Error` are defined internally. External errors provide structured codes (e.g., `.invalidArgument`, `.notFound`) and messages, whereas internal errors focus on compile-time type safety within specific modules.

### How does the DNS subsystem report resolution failures?

The DNS subsystem uses `DNSResolverError` (defined in [`Types.swift`](https://github.com/apple/container/blob/main/Types.swift)) and `DNSBindError` (defined in [`DNSBindError.swift`](https://github.com/apple/container/blob/main/DNSBindError.swift)) to distinguish between query validation failures and record binding issues. Both conform to `CustomStringConvertible` and include descriptions that align with DNS RFC error codes, making network-level failures diagnosable without digging through implementation details.

### What error handling pattern does apple/container use for plugin management?

`PluginsService` defines `PluginsService.Error` with cases for `pluginNotFound` and `pluginNotLoaded`. When `load(name:)` fails, it throws these specific errors rather than generic failures, allowing callers to distinguish between missing binaries and load-time crashes using Swift pattern matching in catch blocks.