---
title: "What does purchaseInvalidError (code 4) mean in the purchases SDK?"
description: "purchaseInvalidError (code 4) means one or more arguments of the purchase are not valid. Check the product, offer and options you pass, and read the underlying error."
url: https://revenuedot.app/docs/errors/sdk-purchase-invalid-error
---

# What does purchaseInvalidError (code 4) mean in the purchases SDK?

The purchases SDK raises purchaseInvalidError (code 4) when the store or the backend says an argument of the purchase is not valid.

## Quick facts

| | |
|---|---|
| Error | `ErrorCode.purchaseInvalidError` (iOS), `PurchasesErrorCode.PurchaseInvalidError` (Android), code 4 |
| Where | Purchases SDK (iOS, Android and the hybrid SDKs built on them) |
| What the vendor says | One or more of the arguments provided are invalid. |

## Cause

- Android: Play Billing `DEVELOPER_ERROR`, the code Google uses for incorrect use of the API, maps here.
- StoreKit 2: `StoreKitError.unsupported` maps here when the SDK is built with Swift 6.1 or later.
- The backend answered a code the SDK treats as an invalid purchase request, such as 7105 (invalid payment mode) or 7106 (missing Google product ID), or an invalid web redemption token.

## Fix

1. Read the underlying error and the debug message; they name the invalid argument.
2. Check the product, offer and options you pass against what is configured in the store and on the server.
3. On Android, check for a signed build and a non-empty product list, as Google lists for `DEVELOPER_ERROR`.
4. Do not retry with the same arguments; the result will not change.

## Example

```swift
// The purchases SDK throws `ErrorCode` values; match the one you handle and let the rest fall through.
func handle(_ error: Error) {
    guard let code = error as? ErrorCode else {
        print("Not a purchases SDK error: \(error)")
        return
    }
    switch code {
    case .purchaseInvalidError:
        // A bug in the arguments: log the underlying error and fix the call, do not retry.
        print("The purchase arguments are invalid")
    default:
        print("Other purchases error: \(code.description)")
    }
}
```

*Compile-checked: `npm run check:snippets` type-checks this snippet with `swiftc` together with the `ErrorCode.swift` file of the RevenueDot `purchases-ios` fork (checked 2026-10-03).*

## How the RevenueDot SDK reports it

Deep dive: [revenuedot.app/errors/purchase-invalid-error](https://revenuedot.app/errors/purchase-invalid-error).

## Related

- [What does Play Billing DEVELOPER_ERROR (5) mean?](https://revenuedot.app/docs/errors/play-billing-developer-error.md)
- [What does StoreKitError.unsupported mean?](https://revenuedot.app/docs/errors/storekit-error-unsupported.md)
- [What does configurationError (code 23) mean in the purchases SDK?](https://revenuedot.app/docs/errors/sdk-configuration-error.md)
- [What RevenueDot's API errors mean (server codes)](https://revenuedot.app/docs/api/errors.md)

## Source

- [RevenueDot purchases-ios: ErrorCode.swift (the iOS ErrorCode enum)](https://github.com/revenuedot/purchases-ios/blob/revenuedot/main-patches/Sources/Generated/ErrorCode.swift)
- [RevenueDot purchases-android: PurchasesErrorCode.kt (the Android enum)](https://github.com/revenuedot/purchases-android/blob/revenuedot/main-patches/purchases/src/main/kotlin/generated/com/revenuecat/purchases/PurchasesErrorCode.kt)
- [RevenueDot purchases-ios: StoreKitError+Extensions.swift](https://github.com/revenuedot/purchases-ios/blob/revenuedot/main-patches/Sources/Error%20Handling/StoreKitError%2BExtensions.swift)
- [RevenueDot purchases-android: google/errors.kt (Play Billing mapping)](https://github.com/revenuedot/purchases-android/blob/revenuedot/main-patches/purchases/src/main/kotlin/com/revenuecat/purchases/google/errors.kt)
- [RevenueDot purchases-ios: BackendErrorCode.swift (backend code mapping)](https://github.com/revenuedot/purchases-ios/blob/revenuedot/main-patches/Sources/Error%20Handling/BackendErrorCode.swift)

Checked: 2026-10-03
