Skip to main content

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.
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.

Definition

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

CaseAssociated valueMeaning
.transport(TransportError)nestedConnectivity layer failed (network or local persistence).
.protocol(ProtocolError)nestedThe request reached the server but the exchange failed (bad status, server error, or undecodable body).
.integration(IntegrationError)nestedThe SDK was misused or misconfigured.
.domain(String)StringA client-side business-rule violation, carrying a human-readable message.

Nested cases

CaseAssociated valuesDescription
.transport(.network(Error))underlying ErrorNo internet, timeout, or connection failure.
.transport(.persistence(Error))underlying ErrorLocal 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?, StringServer returned a structured error (its own domain error).
.protocol(.decoding(Error))underlying ErrorA 2xx response body didn’t match the expected schema.
.integration(.notConfigured)noneconfigure(apiKey:) was not called before use.
.integration(.invalidApiKey)noneThe API key was empty or malformed.
.integration(.invalidURL)noneThe SDK could not build a valid request URL.
.domain(String)StringClient 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:
if let underlying = encoreError.underlying {
    // The original URLSession / decoding error, when one exists.
}

Handling errors

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()
        }
    }
}
  • NotGrantedReason — business outcomes (dismiss, no offers, experiment control, unsupported OS). These are not errors.
  • PresentationResult — the value returned by try await show().
The most common “failure” is not an error at all — it’s the user declining an offer, surfaced as a NotGrantedReason. Reserve do/catch for genuine transport, protocol, and integration failures.