Transaction.finish() is a no-op on iOS 27 beta 5; purchase() then replays the same transaction forever

Transaction.finish() doesn't clear a transaction on iOS 27 beta 5 — worked correctly through beta 4 — every repeat purchase after the first replays the same transaction with no confirmation sheet and no charge.

StoreKit.Transaction.finish() does not clear a transaction on iOS 27 beta 5. The transaction remains in Transaction.unfinished indefinitely, and every subsequent Product.purchase() call for that product returns the same stale transaction instead of starting a new purchase — with no confirmation sheet, no charge, and no way for the app to tell it apart from a genuine purchase.

Because the replayed result is .success carrying a VerificationResult that verifies normally, an app has no supported signal that nothing was bought. The only distinguishing traits are that the id and purchaseDate are unchanged and the call returns in ~10ms instead of making a server round-trip.

Consequence: a consumable product can be purchased exactly once per device. Every later attempt silently no-ops while appearing to succeed.

Steps to Reproduce

On a device running iOS 27 beta 5, sign in to a newly created Sandbox Apple Account (Settings → Apps → App Store → Sandbox Account) with no prior purchase history. Install and launch a development build of an app offering a consumable IAP. Confirm Transaction.unfinished is empty. Purchase the consumable. The confirmation sheet appears and the purchase completes normally. await transaction.finish() on the returned transaction. Enumerate Transaction.unfinished again. Purchase the same consumable a second time. Expected Results Step 6: Transaction.unfinished is empty — the transaction was finished. Step 7: a confirmation sheet appears and a new transaction is created, with a new id and a current purchaseDate. Actual Results Step 6: the just-finished transaction is still listed in Transaction.unfinished. Step 7: no confirmation sheet appears. purchase() returns .success in ~0.01s carrying the same transaction — identical id and identical purchaseDate — and nothing is charged. This repeats indefinitely. Re-fetching the transaction from Transaction.unfinished and calling finish() on that instance does not clear it either, so there is no app-side way to drain the queue.

Diagnostic Log

Virgin sandbox account, empty queue, three consecutive taps on one product:

unfinished before tip.small: []
purchase() returned after 18.10s
tip.small: id=2000001221113013 purchaseDate=2026-08-13 22:36:26 +0000
--- await transaction.finish() ---
unfinished after finishing 2000001221113013: [small#2000001221113013]
unfinished before tip.small: [small#2000001221113013]
purchase() returned after 0.01s
tip.small: id=2000001221113013 purchaseDate=2026-08-13 22:36:26 +0000
unfinished before tip.small: [small#2000001221113013]
purchase() returned after 0.01s
tip.small: id=2000001221113013 purchaseDate=2026-08-13 22:36:26 +0000

The first call is a genuine purchase (18s round-trip, sheet shown). The transaction survives its own finish(). Calls two and three are replays of it.

Notes

Not reproducible against a local .storekit configuration in the Simulator, which always presents the confirmation sheet. Requires Apple's sandbox. Also reproduces on a TestFlight build billed to a real Apple ID, where it is worse: TestFlight purchase history cannot be reset, so the affected products stay permanently stuck for that account. It survives deleting and reinstalling the app, and a device reboot. Possibly the same underlying issue as the unanswered report at https://developer.apple.com/forums/thread/808648 (iOS 26/18, Nov 2025).

Configuration

  • Device: iPhone 16 Pro Max
  • OS: iOS 27 beta 5
  • Products: consumable in-app purchases
  • API: StoreKit 2 (Product.purchase(), Transaction.finish(), Transaction.unfinished)
  • Device: iPhone 16 Pro Max
  • OS: iOS 27 beta 5

This was my first post ever. I messed up the formatting in most of my post. Let me try that agin 🙂

Description

StoreKit.Transaction.finish() does not clear a transaction on iOS 27 beta 5. The transaction remains in Transaction.unfinished indefinitely, and every subsequent Product.purchase() call for that product returns the same stale transaction instead of starting a new purchase — with no confirmation sheet, no charge, and no way for the app to tell it apart from a genuine purchase.

Because the replayed result is .success carrying a VerificationResult that verifies normally, an app has no supported signal that nothing was bought. The only distinguishing traits are that the id and purchaseDate are unchanged and the call returns in ~10ms instead of making a server round-trip.

Consequence: a consumable product can be purchased exactly once per device. Every later attempt silently no-ops while appearing to succeed.

Steps to Reproduce

  1. On a device running iOS 27 beta 5, sign in to a newly created Sandbox Apple Account (Settings → Apps → App Store → Sandbox Account) with no prior purchase history.
  2. Install and launch a development build of an app offering a consumable IAP.
  3. Confirm Transaction.unfinished is empty.
  4. Purchase the consumable. The confirmation sheet appears and the purchase completes normally.
  5. await transaction.finish() on the returned transaction.
  6. Enumerate Transaction.unfinished again.
  7. Purchase the same consumable a second time.

Expected Results

  • Step 6: Transaction.unfinished is empty — the transaction was finished.

  • Step 7: a confirmation sheet appears and a new transaction is created, with a new id and a current purchaseDate.

Actual Results

  • Step 6: the just-finished transaction is still listed in Transaction.unfinished.
  • Step 7: no confirmation sheet appears. purchase() returns .success in ~0.01s carrying the same transaction — identical id and identical purchaseDate — and nothing is charged. This repeats indefinitely.

Re-fetching the transaction from Transaction.unfinished and calling finish() on that instance does not clear it either, so there is no app-side way to drain the queue.

Diagnostic Log

Virgin sandbox account, empty queue, three consecutive taps on one product:

unfinished before tip.small: []
purchase() returned after 18.10s
tip.small: id=2000001221113013 purchaseDate=2026-08-13 22:36:26 +0000
--- await transaction.finish() ---
unfinished after finishing 2000001221113013: [small#2000001221113013]

unfinished before tip.small: [small#2000001221113013]
purchase() returned after 0.01s
tip.small: id=2000001221113013 purchaseDate=2026-08-13 22:36:26 +0000

unfinished before tip.small: [small#2000001221113013]
purchase() returned after 0.01s
tip.small: id=2000001221113013 purchaseDate=2026-08-13 22:36:26 +0000

The first call is a genuine purchase (18s round-trip, sheet shown). The transaction survives its own finish(). Calls two and three are replays of it.

Notes

  • Not reproducible against a local .storekit configuration in the Simulator, which always presents the confirmation sheet. Requires Apple's sandbox.

  • Also reproduces on a TestFlight build billed to a real Apple ID, where it is worse: TestFlight purchase history cannot be reset, so the affected products stay permanently stuck for that account. It survives deleting and reinstalling the app, and a device reboot.

  • Possibly the same underlying issue as the unanswered report at https://developer.apple.com/forums/thread/808648 (iOS 26/18, Nov 2025).

  • A functionally identical report — finish() not clearing a transaction, repeat purchases breaking — was filed against iOS 26 beta 3 in July 2025: https://developer.apple.com/forums/thread/792594. Also unresolved on record. This looks like a StoreKit regression class that recurs across beta cycles rather than a one-off.

  • Every StoreKit "Resolved Issue" in the iOS 27 beta 1–5 release notes is scoped to StoreKit Testing in Xcode (SKTestSession / Transaction Manager / local .storekit config) — none touch the real sandbox purchase path this report is about. If fix verification for this cycle has been leaning on that local-testing path, that would explain why a regression here could ship across multiple betas unnoticed.

Configuration

  • Device: iPhone 16 Pro Max
  • OS: iOS 27 beta 5
  • Products: consumable in-app purchases
  • API: StoreKit 2 (Product.purchase(), Transaction.finish(), Transaction.unfinished)
Transaction.finish() is a no-op on iOS 27 beta 5; purchase() then replays the same transaction forever
 
 
Q