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

# Errors

> The EncoreError hierarchy thrown by the Encore SDK

## EncoreError

`EncoreError` is a **sealed, nested enum**. Errors surface by being **thrown** from `try await placement(_:).show()` (and other `throws` APIs like `revokeEntitlements()`) — they are *not* delivered as a `NotGrantedReason`. User dismissals and "no offers" are business outcomes, not errors; see [NotGrantedReason](./not-granted-reason).

<Warning>
  Never block user actions on an SDK error. Always provide a fallback path so the user can complete their intended action — your `onPassthrough` handler already runs for not-granted outcomes; wrap `try await show()` in `do/catch` and proceed on error too.
</Warning>

### Definition

```swift theme={null}
public enum EncoreError: Error, LocalizedError, Sendable {
    case transport(TransportError)      // "The road is broken" — connectivity
    case `protocol`(ProtocolError)      // "The language failed" — HTTP/API
    case integration(IntegrationError)  // "SDK misused" — config/programmer error
    case domain(String)                 // Client business-rule violation (message only)

    public enum TransportError: Error, Sendable {
        case network(Error)       // No connectivity, timeout, connection failed
        case persistence(Error)   // Local storage read/write failure
    }

    public enum ProtocolError: Error, Sendable {
        case http(status: Int, message: String?)        // Non-2xx, body unreadable
        case api(status: Int, code: String?, message: String) // Structured server error
        case decoding(Error)                              // 2xx body didn't match schema
    }

    public enum IntegrationError: Error, Sendable {
        case notConfigured    // configure() not called before use
        case invalidApiKey    // Empty / malformed API key
        case invalidURL       // Failed to construct a request URL
    }
}
```

### Top-level cases

| Case                             | Associated value | Meaning                                                                                                 |
| -------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------- |
| `.transport(TransportError)`     | nested           | Connectivity layer failed (network or local persistence).                                               |
| `.protocol(ProtocolError)`       | nested           | The request reached the server but the exchange failed (bad status, server error, or undecodable body). |
| `.integration(IntegrationError)` | nested           | The SDK was misused or misconfigured.                                                                   |
| `.domain(String)`                | `String`         | A client-side business-rule violation, carrying a human-readable message.                               |

### Nested cases

| Case                                    | Associated values          | Description                                                |
| --------------------------------------- | -------------------------- | ---------------------------------------------------------- |
| `.transport(.network(Error))`           | underlying `Error`         | No internet, timeout, or connection failure.               |
| `.transport(.persistence(Error))`       | underlying `Error`         | Local storage (cache/outbox) read or write failed.         |
| `.protocol(.http(status:message:))`     | `Int`, `String?`           | Non-2xx response with an unreadable/unexpected body.       |
| `.protocol(.api(status:code:message:))` | `Int`, `String?`, `String` | Server returned a structured error (its own domain error). |
| `.protocol(.decoding(Error))`           | underlying `Error`         | A 2xx response body didn't match the expected schema.      |
| `.integration(.notConfigured)`          | none                       | `configure(apiKey:)` was not called before use.            |
| `.integration(.invalidApiKey)`          | none                       | The API key was empty or malformed.                        |
| `.integration(.invalidURL)`             | none                       | The SDK could not build a valid request URL.               |
| `.domain(String)`                       | `String`                   | Client business-rule violation; the string describes it.   |

### Helpers

Every `EncoreError` conforms to `LocalizedError`, so `errorDescription` gives a developer-readable summary. `transport` and `protocol(.decoding)` errors also expose the wrapped system error via the `underlying` property:

```swift theme={null}
if let underlying = encoreError.underlying {
    // The original URLSession / decoding error, when one exists.
}
```

## Handling errors

```swift theme={null}
func cancelTapped() {
    Task {
        do {
            let result = try await Encore.placement("cancel_flow").show()
            switch result {
            case .granted(let entitlement):
                applyEntitlement(entitlement)
            case .notGranted:
                // User dismissed or no offers — proceed with the original action.
                proceedWithCancellation()
            }
        } catch let error as EncoreError {
            switch error {
            case .integration(.notConfigured):
                assertionFailure("Call Encore.shared.configure(apiKey:) at launch")
            case .transport(.network(let underlying)):
                Logger.log("Network error: \(underlying.localizedDescription)")
            case .protocol(.api(_, let code, let message)):
                Logger.log("API error (\(code ?? "unknown")): \(message)")
            default:
                Logger.log(error.errorDescription ?? "Encore error")
            }
            // Always let the user proceed.
            proceedWithCancellation()
        } catch {
            proceedWithCancellation()
        }
    }
}
```

## Related Types

* [NotGrantedReason](./not-granted-reason) — business outcomes (dismiss, no offers, experiment control, unsupported OS). These are **not** errors.
* [PresentationResult](./presentation-result) — the value returned by `try await show()`.

<Tip>
  The most common "failure" is not an error at all — it's the user declining an offer, surfaced as a [`NotGrantedReason`](./not-granted-reason). Reserve `do/catch` for genuine transport, protocol, and integration failures.
</Tip>
