# How to Handle Errors in CodexBar Scanning: A Type-Driven Approach

> Master CodexBar scanning error handling with localized enums and centralized orchestration via ProviderFetchPlan for robust AI data aggregation. Learn how to manage errors effectively.

- Repository: [Peter Steinberger/CodexBar](https://github.com/steipete/CodexBar)
- Tags: how-to-guide
- Published: 2026-07-10

---

**CodexBar handles scanning errors through provider-specific enums conforming to `LocalizedError`, centralized orchestration via `ProviderFetchPlan`, and observable UI propagation to ensure robust data aggregation across dozens of AI providers.**

Handling network failures, authentication issues, and parsing errors is critical when gathering usage data from multiple AI services. In the **steipete/CodexBar** repository, the scanning pipeline implements a typed-error-per-provider strategy combined with centralized error aggregation to maintain code maintainability and UI stability. This article examines how to handle errors in CodexBar scanning by analyzing the source code architecture from low-level probes to high-level SwiftUI updates.

## Provider-Specific Error Enums

Every probe in CodexBar defines a dedicated error enum that conforms to `LocalizedError`, `Sendable`, and often `Equatable`. This typed approach ensures exhaustive error handling and human-readable descriptions without fragile string matching.

For example, the Zed provider defines `ZedStatusProbeError` in [`Sources/CodexBarCore/Providers/Zed/ZedStatusProbe.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/Zed/ZedStatusProbe.swift):

```swift
public enum ZedStatusProbeError: LocalizedError, Sendable, Equatable {
    case unauthorized
    case notSignedIn
    case invalidServerURL
    case parseFailed(String)
    case apiError(Int, String)
    // Additional cases...
}

```

Similarly, the Windsurf provider implements `WindsurfStatusProbeError` in [`Sources/CodexBarCore/Providers/Windsurf/WindsurfStatusProbe.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/Windsurf/WindsurfStatusProbe.swift), while Claude uses `ClaudeUsageError` in [`Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift).

These enums categorize failures into distinct types:

- **Network errors**: `URLError(.cannotConnectToHost)`, `CancellationError`
- **Authentication failures**: `unauthorized`, `notSignedIn`, `invalidCookie`
- **Parsing issues**: `parseFailed(String)`, `apiError(Int, String)`
- **Configuration problems**: `invalidEndpointOverride`, `untrustedServerConfiguration`
- **Quota limitations**: `quotaExceeded`, `usageUnavailable`

Because each enum adopts `LocalizedError`, the `errorDescription` property provides consistent, user-friendly messaging that the UI can display directly.

## Centralized Error Orchestration

While individual probes throw typed errors, the **ProviderFetchPlan** and **ProviderCandidateRetryRunner** classes manage centralized error aggregation and retry logic.

### ProviderFetchPlan

Located in [`Sources/CodexBarCore/Providers/ProviderFetchPlan.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/ProviderFetchPlan.swift), this class defines the sequence of fetchers for a given provider and wraps individual errors in `ProviderFetchError`. This thin wrapper also conforms to `LocalizedError`, preserving human-readable descriptions while unifying the error type for the orchestration layer.

### ProviderCandidateRetryRunner

Defined in [`Sources/CodexBarCore/Providers/ProviderCandidateRetryRunner.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/ProviderCandidateRetryRunner.swift), this runner executes candidate fetchers with exponential backoff. It distinguishes between **recoverable** errors (temporary network glitches that trigger retries) and **irrecoverable** errors (malformed API keys that short-circuit the scan). Irrecoverable failures are immediately surfaced to the UI via `Issue.record(_:)` entries.

## Propagating Errors to the UI

The scanning pipeline returns `Result<ProbeData, ProviderFetchError>` to the **StatusItemController**, which bridges errors to the SwiftUI interface.

When a failure occurs, the controller performs three actions:

1. Calls `error.localizedDescription` (leveraging `LocalizedError` conformance) to obtain a friendly string
2. Stores the error in the `@Observable` model `StatusItemState`, triggering automatic SwiftUI updates
3. Optionally activates UI hints, such as flashing warning icons, based on error severity

This architecture enables context-specific UI actions. For instance, an `invalidEndpointOverride` error can trigger an "Open Settings" button, while network errors might display a "Retry" option.

## Testing Error Handling Paths

Every error enum includes comprehensive unit tests to prevent regression. The test suite verifies that the orchestration layer correctly propagates each failure type.

Key test files include:

- [`Tests/CodexBarTests/ZedStatusProbeTests.swift`](https://github.com/steipete/CodexBar/blob/main/Tests/CodexBarTests/ZedStatusProbeTests.swift): Covers `invalidServerURL`, `unauthorized`, and cancellation errors using `#expect(throws:)` syntax
- [`Tests/CodexBarTests/WindsurfStatusProbeTests.swift`](https://github.com/steipete/CodexBar/blob/main/Tests/CodexBarTests/WindsurfStatusProbeTests.swift): Tests SQLite-related failures including `openFailed` and `prepareFailed`
- [`Tests/CodexBarTests/ProviderCandidateRetryRunnerTests.swift`](https://github.com/steipete/CodexBar/blob/main/Tests/CodexBarTests/ProviderCandidateRetryRunnerTests.swift): Validates retry logic with mock `TestError` instances
- [`Tests/CodexBarTests/StatusProbeTests.swift`](https://github.com/steipete/CodexBar/blob/main/Tests/CodexBarTests/StatusProbeTests.swift): Verifies complex scenarios such as "browser scan stops importing after later browser succeeds"

These tests ensure that future refactors cannot silently swallow failure cases or break error propagation chains.

## Code Examples

### Handling Provider-Specific Errors

When invoking a probe directly, catch the specific error type for granular handling:

```swift
do {
    let result = try await ZedStatusProbe().scan()
    // Update UI with successful data
} catch let error as ZedStatusProbeError {
    logger.error("Zed probe failed: \(error.localizedDescription)")
    statusItem.showError(error) // Updates UI badge
} catch {
    logger.error("Unexpected error: \(error)")
    statusItem.showGenericError()
}

```

### Using ProviderFetchPlan for Centralized Handling

For coordinated fetching with automatic retry logic:

```swift
let plan = ProviderFetchPlan(provider: .zed, candidates: [.statusProbe, .tokenFetcher])
do {
    let data = try await plan.run()
    statusItem.update(with: data)
} catch let fetchError as ProviderFetchError {
    // All provider-specific errors wrapped uniformly
    statusItem.showError(fetchError)
}

```

### SwiftUI Error Display

The observable state model enables reactive error presentation:

```swift
@Observable final class StatusItemState {
    var errorMessage: String? = nil
    // ...
}

// In the view:
if let message = state.errorMessage {
    Text(message)
        .foregroundColor(.red)
        .font(.caption)
}

```

## Summary

- **Type safety**: Every provider defines a specific error enum (e.g., `ZedStatusProbeError`, `ClaudeUsageError`) conforming to `LocalizedError` for exhaustive handling and human-readable descriptions.
- **Centralized orchestration**: `ProviderFetchPlan` and `ProviderCandidateRetryRunner` manage retries, distinguish recoverable from irrecoverable errors, and wrap failures in `ProviderFetchError`.
- **UI integration**: The `StatusItemController` propagates errors through `StatusItemState`, enabling SwiftUI to display context-specific actions and status badges.
- **Test coverage**: Comprehensive suites in [`ZedStatusProbeTests.swift`](https://github.com/steipete/CodexBar/blob/main/ZedStatusProbeTests.swift), [`WindsurfStatusProbeTests.swift`](https://github.com/steipete/CodexBar/blob/main/WindsurfStatusProbeTests.swift), and [`ProviderCandidateRetryRunnerTests.swift`](https://github.com/steipete/CodexBar/blob/main/ProviderCandidateRetryRunnerTests.swift) verify error propagation using `#expect(throws:)` assertions.

## Frequently Asked Questions

### What error types does CodexBar use for provider scanning?

CodexBar uses provider-specific enums such as `ZedStatusProbeError`, `WindsurfStatusProbeError`, and `ClaudeUsageError`. Each enum conforms to `LocalizedError`, `Sendable`, and `Equatable` to provide type-safe error handling and human-readable descriptions for network, authentication, parsing, and configuration failures.

### How does CodexBar handle retry logic when a scan fails?

The `ProviderCandidateRetryRunner` class in [`Sources/CodexBarCore/Providers/ProviderCandidateRetryRunner.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/ProviderCandidateRetryRunner.swift) implements exponential backoff for recoverable errors like temporary network glitches. Irrecoverable errors such as invalid API keys short-circuit immediately and propagate to the UI without retry attempts.

### Can the UI display different actions based on specific error types?

Yes. Because all errors are typed enums conforming to `LocalizedError`, the `StatusItemController` can inspect specific cases (e.g., `invalidEndpointOverride`) and trigger context-appropriate actions like "Open Settings" buttons. This avoids fragile string-matching and ensures type-safe UI logic.

### Where are the error handling tests located in the CodexBar repository?

Error handling tests are distributed across several files: [`Tests/CodexBarTests/ZedStatusProbeTests.swift`](https://github.com/steipete/CodexBar/blob/main/Tests/CodexBarTests/ZedStatusProbeTests.swift) for Zed-specific errors, [`Tests/CodexBarTests/WindsurfStatusProbeTests.swift`](https://github.com/steipete/CodexBar/blob/main/Tests/CodexBarTests/WindsurfStatusProbeTests.swift) for SQLite-related failures, and [`Tests/CodexBarTests/ProviderCandidateRetryRunnerTests.swift`](https://github.com/steipete/CodexBar/blob/main/Tests/CodexBarTests/ProviderCandidateRetryRunnerTests.swift) for retry logic validation. These use Swift Testing's `#expect(throws:)` syntax to verify correct error propagation.