---
title: "What does Product.PurchaseError.productUnavailable mean?"
description: "Product.PurchaseError.productUnavailable means the product cannot be bought. Check its state in App Store Connect, its availability by region and its identifier."
url: https://revenuedot.app/docs/errors/storekit-purchase-error-product-unavailable
---

# What does Product.PurchaseError.productUnavailable mean?

Product.PurchaseError.productUnavailable means the App Store reports that this product is not available to buy.

## Quick facts

| | |
|---|---|
| Error | `Product.PurchaseError.productUnavailable` |
| Where | StoreKit 2, Swift (`Product.purchase(options:)`) |
| Available since | iOS 15.0, iPadOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, visionOS 1.0 |
| What the vendor says | The product is not available. |

## Cause

- The App Store has the product but will not sell it to this customer right now. Apple's page for the case gives no further reason.
- Apple notes that if an identifier is invalid or the App Store cannot find it, `Product.products(for:)` leaves it out of the result instead of throwing ([products(for:)](https://developer.apple.com/documentation/storekit/product/products%28for:%29)). A product you hold but cannot buy is a different state from one that never loaded.
- Products are sold per region, and Apple tells developers to keep their own list of identifiers and the storefronts where they are available ([Storefront](https://developer.apple.com/documentation/storekit/storefront)).

## Fix

1. Check the product in App Store Connect: it must exist, have complete metadata and be available in the customer's region.
2. Compare the identifier in your code character by character with the one in App Store Connect.
3. Reload products and compare the IDs you asked for with the IDs that came back, to see which one is missing.
4. Hide or disable the buy button for the product until it loads, and do not retry the same call in a loop.

## Example

```swift
import StoreKit

// Compare what you asked for with what came back, so a missing product is a log line instead of a silent dead button.
func buy(id: String) async {
    do {
        guard let product = try await Product.products(for: [id]).first else {
            print("The App Store returned no product for \(id); check the identifier and availability")
            return
        }
        _ = try await product.purchase()
    } catch Product.PurchaseError.productUnavailable {
        print("\(id) exists but cannot be bought right now")
    } catch {
        print("Purchase failed: \(error)")
    }
}
```

*Compile-checked: `npm run check:snippets` type-checks this snippet with `swiftc` against the Apple SDK (macOS target, checked 2026-10-03).*

## How the RevenueDot SDK reports it

The RevenueDot `purchases-ios` fork maps `Product.PurchaseError.productUnavailable` to `ErrorCode.productNotAvailableForPurchaseError` (code 5). In RevenueDot, make sure the product's store identifier equals the App Store identifier. See [what productNotAvailableForPurchaseError means](https://revenuedot.app/docs/errors/sdk-product-not-available-for-purchase-error.md).

## Related

- [What does productNotAvailableForPurchaseError (code 5) mean in the purchases SDK?](https://revenuedot.app/docs/errors/sdk-product-not-available-for-purchase-error.md)
- [What does StoreKitError.notAvailableInStorefront mean?](https://revenuedot.app/docs/errors/storekit-error-not-available-in-storefront.md)
- [What does Play Billing ITEM_UNAVAILABLE (4) mean?](https://revenuedot.app/docs/errors/play-billing-item-unavailable.md)

## Source

- [Apple: Product.products(for:)](https://developer.apple.com/documentation/storekit/product/products%28for:%29)
- [Apple: Product.PurchaseError.productUnavailable](https://developer.apple.com/documentation/storekit/product/purchaseerror/productunavailable)
- [Apple: Product.PurchaseError](https://developer.apple.com/documentation/storekit/product/purchaseerror)
- [RevenueDot purchases-ios: StoreKitError+Extensions.swift (how the SDK maps StoreKit 2 errors)](https://github.com/revenuedot/purchases-ios/blob/revenuedot/main-patches/Sources/Error%20Handling/StoreKitError%2BExtensions.swift)

Checked: 2026-10-03
