> ## Documentation Index
> Fetch the complete documentation index at: https://primer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# PrimerError

> Error details with a diagnostics ID and recovery suggestion

<Warning>
  Primer Checkout iOS SDK is currently in **beta** (v3.0.0-beta.1).
  The API is subject to change before the stable release.
</Warning>

`PrimerError` is the error type delivered when a payment or checkout fails. Every error carries a stable `errorId` for programmatic handling, a `diagnosticsId` to share with Primer support, and (where applicable) a `recoverySuggestion` describing how to recover.

```swift theme={"dark"}
public enum PrimerError: PrimerErrorProtocol {
    public var errorId: String { get }
    public var diagnosticsId: String { get }
    public var recoverySuggestion: String? { get }
    public var errorDescription: String? { get }
    public var errorUserInfo: [String: Any] { get }
    public var underlyingErrorCode: String? { get }
}
```

<Info>
  `PrimerError` conforms to `LocalizedError` and `CustomNSError`, so you also get `localizedDescription` for free and can bridge it to `NSError` when needed.
</Info>

## How errors are delivered

You never construct a `PrimerError` yourself. The SDK delivers it to you through one of two channels, depending on how you present checkout.

| Channel            | Where the error arrives                                                                                                                                                                                                                                                                                     |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SwiftUI state      | [`PrimerCheckoutState.failure(PrimerError)`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-state) — receive the final state through the `.primerCheckoutSession(session) { state in ... }` modifier's completion closure (or `PrimerCheckout(clientToken:) { state in ... }`) and switch on `.failure`. |
| Presenter delegate | [`PrimerCheckoutPresenterDelegate`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-presenter) `primerCheckoutPresenterDidFailWithError(_:)` for UIKit / presenter-driven integrations.                                                                                                                   |

See [Handle the payment result](/docs/sdk/ios-checkout/v3.0.0-beta/guides/handle-payment-result) for the full success / failure / dismissed flow.

## Properties

| Property              | Type            | Description                                                                                                                                                                                   |
| --------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `errorId`             | `String`        | Stable, kebab-case identifier for the error category (for example `"invalid-client-token"`, `"payment-cancelled"`, `"apple-pay-no-cards-in-wallet"`). Use this for programmatic branching.    |
| `diagnosticsId`       | `String`        | Unique per-occurrence diagnostics ID. Log it and provide it to Primer support when investigating an issue.                                                                                    |
| `recoverySuggestion`  | `String?`       | Suggested recovery action when one applies (for example "Check if the token you have provided is a valid token"). `nil` when no recovery is available (for example a user-cancelled payment). |
| `errorDescription`    | `String?`       | Human-readable description suitable for logging. Includes the `errorId` and `diagnosticsId`. Also surfaced as `localizedDescription` via `LocalizedError`.                                    |
| `errorUserInfo`       | `[String: Any]` | `NSError` user-info dictionary. Includes `"diagnosticsId"` and a `"createdAt"` timestamp.                                                                                                     |
| `underlyingErrorCode` | `String?`       | An underlying provider error code when one is available. Currently populated only for NOL Pay errors; `nil` otherwise.                                                                        |

<Warning>
  `errorDescription` and `localizedDescription` are intended for logging and diagnostics, not for display to shoppers. Show your own localized, branded messaging in the UI and reserve the SDK description for your logs.
</Warning>

## Handling an error

Receive the checkout state through the completion closure and, in the `.failure` branch, log the `diagnosticsId` and `errorId`. Branch on `errorId` only when you need behavior specific to a category (for example treating a cancellation differently from a hard failure).

```swift theme={"dark"}
import SwiftUI
import PrimerSDK

struct CheckoutScreen: View {
    @StateObject private var session = PrimerCheckoutSession(clientToken: clientToken)

    var body: some View {
        ScrollView {
            PrimerCardForm()
        }
        .primerCheckoutSession(session) { state in
            handle(state)
        }
    }

    private func handle(_ state: PrimerCheckoutState) {
        switch state {
        case let .failure(error):
            handle(error)
        case let .success(result):
            print("Payment completed: \(result.paymentId)")
        case .dismissed, .initializing, .ready:
            break
        @unknown default:
            break
        }
    }

    private func handle(_ error: PrimerError) {
        // Always log the diagnostics ID — share it with Primer support.
        print("Checkout failed [\(error.errorId)]: \(error.localizedDescription)")
        print("Diagnostics ID: \(error.diagnosticsId)")

        switch error.errorId {
        case "payment-cancelled":
            // Shopper backed out — usually no message needed.
            break
        default:
            // Show your own branded, localized error message here.
            showRetryAlert(suggestion: error.recoverySuggestion)
        }
    }
}
```

For a UIKit / presenter integration, the same `PrimerError` arrives through the delegate:

```swift theme={"dark"}
extension CheckoutCoordinator: PrimerCheckoutPresenterDelegate {
    func primerCheckoutPresenterDidFailWithError(_ error: PrimerError) {
        print("Checkout failed [\(error.errorId)] — diagnosticsId: \(error.diagnosticsId)")
        // Present your own error UI; use error.recoverySuggestion to decide whether to offer a retry.
    }
}
```

<Tip>
  When filing a support ticket, include the `diagnosticsId`. It lets Primer trace the exact occurrence of the failure across SDK and backend logs.
</Tip>

## See also

<CardGroup cols={2}>
  <Card title="PrimerCheckoutState" icon="signal" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-state">
    The checkout state that delivers `.failure(PrimerError)`.
  </Card>

  <Card title="Handle the payment result" icon="circle-check" href="/docs/sdk/ios-checkout/v3.0.0-beta/guides/handle-payment-result">
    Handle success, failure, and dismissal end to end.
  </Card>

  <Card title="PrimerCheckoutPresenter" icon="square-arrow-up-right" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-presenter">
    Receive failures through the presenter delegate.
  </Card>

  <Card title="ValidationResult" icon="list-check" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/common/validation-result">
    Inline field validation, distinct from checkout errors.
  </Card>
</CardGroup>
