SDK error · code 1

purchaseCancelledError (error code 1): Purchase cancelled

What it means

purchaseCancelledError (code 1) means the customer closed the purchase sheet, so nothing was bought and nothing is broken. Do not show an error. Check the userCancelled flag the SDK passes with it, leave the paywall as it was, and let the customer try again. The Test Store dialog's Cancel button raises it too.

Code

1

iOS (Swift)

ErrorCode.purchaseCancelledError

Android (Kotlin)

PurchasesErrorCode.PurchaseCancelledError

Causes

Why the SDK returns purchaseCancelledError

  • StoreKit 2: the customer dismissed the sheet. StoreKit reports StoreKitError.userCancelled and the SDK maps it here.
  • StoreKit 1: SKError.paymentCancelled or overlayCancelled.
  • Some iOS cancels arrive as an undocumented SKError 907 whose underlying AMSError code is 6 (payment sheet failed). The SDK treats that as a cancel as well (source).
  • Android: Play Billing returns USER_CANCELED when the customer leaves the billing flow (Google docs), and the Android SDK maps it here.
  • The Cancel button in the Test Store purchase dialog on Android raises it too.

Fix

How to fix purchaseCancelledError

  1. 01

    Treat it as an outcome

    Do not show an error dialog. In the Swift async API, read userCancelled on the result. In the completion-handler API and on Android, the callback receives a userCancelled flag next to the error.

  2. 02

    Keep the screen as it was

    Leave the paywall open with its products loaded so the customer can pick again. Do not reload offerings.

  3. 03

    Count it separately

    Track cancels apart from failures in your analytics. A cancel is a funnel step, not a bug.

  4. 04

    Check the log if a tester says they did not cancel

    Turn on debug logs and read the underlying error. It shows whether StoreKit or Play Billing reported the cancel.

In your app

How to handle it in code

  • Do not retry for the customer, and do not show an error. The customer chose to stop.
  • Do not grant access. Nothing was bought.
  • Log it at info level, not as an error, so real failures stay visible.
Match the errorSwift · Kotlin
// Swift
do {
  let result = try await Purchases.shared.purchase(package: package)
} catch let error as ErrorCode where error == .purchaseCancelledError {
  // handle purchase cancelled
}

// Kotlin
if (error.code == PurchasesErrorCode.PurchaseCancelledError) { /* ... */ }

On RevenueDot: RevenueDot never sees a cancelled purchase. The SDK stops before it posts a receipt to POST /v1/receipts, so no server setting changes this.

FAQ

purchaseCancelledError: questions people ask

Should I show an error when the user cancels a purchase?

No. A cancel is the customer's choice. Check the userCancelled flag, keep the paywall open, and show nothing.

How do I detect a cancelled purchase in Swift and Kotlin?

In Swift, read userCancelled on the purchase result, or compare the error with ErrorCode.purchaseCancelledError in the completion-handler API. In Kotlin, PurchaseErrorCallback.onError receives the error and a userCancelled boolean.

How do I check for purchaseCancelledError in React Native and Flutter?

In React Native, compare error.code with PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR. In Flutter, convert the PlatformException with PurchasesErrorHelper.getErrorCode(e) and compare the result with PurchasesErrorCode.purchaseCancelledError. The userCancelled field on the React Native error is also true for a cancel.

Get started

Keep the RevenueCat SDK. Change the backend.

RevenueDot answers the same SDK calls with the same error codes. Start free on RevenueDot Cloud, free up to $10,000 a month in tracked revenue.

Already have an account? Sign in · Prefer your own servers? Self-host free