What does VerificationError.invalidDeviceVerification mean in StoreKit 2?

VerificationResult.VerificationError.invalidDeviceVerification means the signed StoreKit 2 value was not generated for the current device.

Quick facts#

Error VerificationResult.VerificationError.invalidDeviceVerification
Where StoreKit 2, Swift (VerificationResult)
Available since iOS 15.0, iPadOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, visionOS 1.0
What the vendor says An error that indicates the signed value wasn't generated for the current device.

Cause#

  • StoreKit 2 returns transactions, renewal information and the app transaction wrapped in a VerificationResult. It checks them for you, and a value that fails is .unverified with the reason as a VerificationError (VerificationResult).
  • Apple's page gives only that definition: the value is signed for another device, so it must not be trusted on this one.
  • invalidDeviceVerification is one of six reasons Apple lists, next to invalidSignature, invalidCertificateChain, invalidDeviceVerification, invalidEncoding, missingRequiredProperties and revokedCertificate.

Fix#

  1. Treat an .unverified result as untrusted. Do not unlock content from it and do not call finish() on it until you have decided what to do.
  2. Do not copy signed transactions between devices and treat them as local proof. Verify on your server instead.
  3. Log the VerificationError and the transaction ID, then check the same transaction on your server with Apple's App Store Server Library or the App Store Server API.
  4. If it only happens in testing, check the test environment (Xcode StoreKit configuration, sandbox account) before changing code.

Example#

Swift
import StoreKit

// Only a verified transaction may unlock content. Log the reason when a transaction is unverified.
func handle(_ result: VerificationResult<Transaction>) {
    switch result {
    case .verified(let transaction):
        print("Unlock \(transaction.productID)")
    case .unverified(let transaction, let error):
        if case .invalidDeviceVerification = error {
            print("The value was not signed for this device for \(transaction.productID); do not unlock")
        } else {
            print("Verification 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 turns an unverified transaction from a purchase or a transaction update into ErrorCode.storeProblemError (code 2) with the VerificationError as the underlying error, and it does not unlock the purchase. When it only reads existing transactions (offline entitlements, transaction history), it logs a warning and skips the unverified ones.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated