Loosely Decoupled
TroubleshootingStorekit

StoreKit Purchase Verifies but currentEntitlements Is Empty in Xcode Testing

StoreKit itself returned nothing, not the verification code, and deleting and reinstalling the app cleared what a new .storekit file didn’t.

A gouache painting of a tired man with headphones round his neck holding up a cyan paid ticket over an empty velvet display case, while a small monkey with a lanyard sits on a pile of old ticket stubs.
On this page

TL;DR

A StoreKit test purchase on a physical device can succeed and verify while Transaction.currentEntitlements comes back empty right after. First find out whether StoreKit returned nothing or your code dropped the result: count every result before you verify it. If the count is zero, delete the app from the device, reinstall it from Xcode and buy again. In the one case tested here, on one iPhone, that cleared it.

Swift
for await result in Transaction.currentEntitlements {
    entitlementCount += 1
    guard let transaction = try? checkVerified(result) else {
        continue
    }
    // ...
}
// The app's log line also prints the Pro state after this count.
print("StoreManager: Entitlements refreshed - \(entitlementCount) from StoreKit")

Tested with

iOS
27.0.1, iPhone
Xcode
27.1 (27A9275)
Framework
StoreKit 2, local .storekit configuration
Date
October 2026

I hit this while preparing a release of a small iPhone app I’m building, which sells one non-consumable Pro upgrade. The purchase sheet said “You’re all set”, and the app stayed locked. This page covers how I separated StoreKit from my own code, what turned out not to matter, and the reinstall that fixed it.

Purchase succeeds, but the upgrade stays locked

On a physical iPhone launched from Xcode with a StoreKit configuration file, the symptoms, in the order they appear:

  1. The purchase sheet said “You’re all set”, and the app logged a verified, unrevoked transaction.
  2. The entitlement refresh straight after it found nothing.
  3. Xcode’s transaction manager, under Debug > StoreKit > Manage Transactions, listed the purchase.
  4. Restore Purchases reported no previous purchases.
  5. Buying again failed with ASDServerErrorDomain 2010.

The two log lines from steps 1 and 2:

Text
StoreManager: Purchase verified - <product-id>, revoked: false
StoreManager: Entitlements refreshed - 0 from StoreKit, Pro: false

I don’t know what ASDServerErrorDomain 2010 means. I couldn’t find it in Apple’s documentation, so treat it as a symptom here, not a diagnosis.

Count entitlements before you verify them

An empty entitlement list can come from two places: StoreKit emitted nothing, or your code discarded what it emitted. A loop that only counts the transactions it keeps can’t tell those apart. A failed verification, a revocation check or a product ID filter all look the same as an empty sequence.

Count each result as it arrives, before any check, as in the code in the answer. In that code, checkVerified is the app’s own verification helper, not a StoreKit API. If that count is zero, the sequence itself was empty and your filtering isn’t the cause. Mine was zero.

The product type matters too, because currentEntitlements doesn’t include every product type. Apple’s currentEntitlements reference (opens in a new tab) says it emits “a transaction for each non-consumable Apple In-App Purchase” and leaves out consumables and refunded or revoked products. Check the product’s type in the .storekit file. Mine was NonConsumable, so it should have appeared.

Placeholder team ID wasn’t the cause

The .storekit file was an older one, written by hand. Its _developerTeamID was the placeholder YOUR_TEAM_ID, and its product and app IDs didn’t match App Store Connect. Sync with App Store Connect failed with “Could not sign in”, even though Xcode was signed in to an Admin account.

That looked like the cause, and fixing it was still worth doing. Apple’s StoreKit testing setup guide (opens in a new tab) has you pick the team and app when you create a synced configuration file. To sync a converted file again, it says to create a new synced file. I replaced the hand-written file with a new synced one. It wasn’t enough on its own. A purchase made after the swap still left the entitlement count at zero.

Entitlement count by environment

Each run used the same build of the app:

EnvironmentEntitlements after purchase
Simulator, iOS 26.5, synced .storekit file1
iPhone, iOS 27.0.1, synced .storekit file, same install as before the swap0
iPhone, iOS 27.0.1, App Store sandbox, scheme with no StoreKit configuration, fresh install1
iPhone, iOS 27.0.1, synced .storekit file, after deleting and reinstalling the app1

The Simulator result alone didn’t separate the device from the OS version, because the Simulator ran an older iOS. The sandbox row answers a narrower question. On iOS 27, against the App Store sandbox, a fresh install logged Entitlements refreshed - 1 from StoreKit, Pro: true. Because that install was fresh too, it doesn’t show whether the sandbox would have returned the entitlement on the install that returned zero. It shows only that a sandbox purchase unlocks on a clean install, in one run.

Delete the app and test again

The last row of the table is the fix. On the one iPhone and iOS build tested, the empty result behaved like test state stored on the device: it survived replacing the configuration file, and deleting the app cleared it. I captured only the before and after, so what that state was, what put it there, and why replacing the file didn’t reset it are unknown.

To clear it:

  1. On the iPhone, delete the app.
  2. In Xcode, run the scheme that has the StoreKit configuration selected.
  3. In the app, tap Restore Purchases before buying anything. With nothing bought, it reports no previous purchases.
  4. Buy the product again.

Check the console. A purchase that unlocks logs a verified transaction followed by a count of one:

Text
StoreManager: Purchase verified - <product-id>, revoked: false
StoreManager: Entitlements refreshed - 1 from StoreKit, Pro: true

Resets that don’t reach the device

xcrun simctl erase all erases every simulator. It doesn’t touch a physical device. For a device, Apple’s guide to testing in-app purchases in Xcode (opens in a new tab) resets a test by deleting the transaction under Debug > StoreKit > Manage Transactions. Whether that reset clears the same state isn’t recorded here; deleting the app is what cleared it.

New articles, by email.

A short note when something new is published.