TestFlight feedback — crash · 2026-03-09T17:18:53.466Z
Tester comment
Tapped a friend
Build context
- Build: 53 (VALID)
- App version: 2.0.1
- Commit: (unresolved — build wasn't from Xcode Cloud)
Device
- Model: iPhone18_2
- OS: 26.4
- Architecture: arm64e
- Locale: en-DK
- Time zone: Europe/Copenhagen
- Connection: WIFI
- Battery: 80%
Crash signature
- Exception Type:
EXC_CRASH (SIGABRT)
- Exception Codes:
0x0000000000000000, 0x0000000000000000
- Termination Reason:
SIGNAL 6 Abort trap: 6
- Triggered by Thread: 0 (main)
The crashing thread is only the abort machinery — an uncaught Objective-C exception unwinding out of the main runloop:
Thread 0 Crashed:
0 libsystem_kernel.dylib __pthread_kill + 8
1 libsystem_pthread.dylib pthread_kill + 268 (pthread.c:1721)
2 libsystem_c.dylib abort + 148 (abort.c:122)
3 libc++abi.dylib __abort_message + 132 (abort_message.cpp:66)
4 libc++abi.dylib demangling_terminate_handler() + 296 (cxa_default_handlers.cpp:77)
5 libobjc.A.dylib _objc_terminate() + 156 (objc-exception.mm:496)
6 libc++abi.dylib std::__terminate(void (*)()) + 16 (cxa_handlers.cpp:59)
7 libc++abi.dylib std::terminate() + 108 (cxa_handlers.cpp:88)
8 CoreFoundation __CFRunLoopPerCalloutARPEnd + 256 (CFRunLoop.c:769)
9 CoreFoundation __CFRunLoopRun + 1976 (CFRunLoop.c:3179)
10 CoreFoundation _CFRunLoopRunSpecificWithOptions + 532 (CFRunLoop.c:3462)
The real call site is in the Last Exception Backtrace, and it is fully symbolicated:
Last Exception Backtrace:
0 CoreFoundation __exceptionPreprocess + 164 (NSException.m:249)
1 libobjc.A.dylib objc_exception_throw + 88 (objc-exception.mm:356)
2 CoreFoundation +[NSException raise:format:] + 128 (NSException.m:0)
3 StoreKit -[SKStoreProductViewController _throwUnsupportedPresentationException] + 72 (SKStoreProductViewController.m:1187)
4 StoreKit -[SKStoreProductViewController _configureForFullScreenPresentationOrThrowException] + 80 (SKStoreProductViewController.m:1180)
5 StoreKit -[SKStoreProductViewController willMoveToParentViewController:] + 40 (SKStoreProductViewController.m:520)
6 UIKitCore UICorePlatformViewHost.removeFromSuperview() + 124 (UICorePlatformViewHost.swift:246)
7 UIKitCore @objc UICorePlatformViewHost.removeFromSuperview() + 36 (<compiler-generated>:0)
8 UIKitCore -[UIView dealloc] + 348 (UIView.m:5308)
9 SwiftUI _UIHostingView.__deallocating_deinit + 420 (UIHostingView.swift:599)
10 SwiftUI @objc _UIHostingView.__deallocating_deinit + 28 (<compiler-generated>:0)
11 libobjc.A.dylib AutoreleasePoolPage::releaseUntil(objc_object**) + 204 (NSObject.mm:1017)
12 libobjc.A.dylib objc_autoreleasePoolPop + 244 (NSObject.mm:2275)
13 CoreFoundation _CFAutoreleasePoolPop + 32 (NSObject.m:859)
14 CoreFoundation __CFRunLoopPerCalloutARPEnd + 48 (CFRunLoop.c:766)
Analysis
The thrown exception is StoreKit's own, and it names its own reason: -[SKStoreProductViewController _throwUnsupportedPresentationException], reached from _configureForFullScreenPresentationOrThrowException. SKStoreProductViewController refuses to be anything but a full-screen modal — it must not be embedded as a child view controller or re-parented — and it enforces that by raising NSException from willMoveToParentViewController:.
Read the frames below the throw and the timing is the whole story:
_UIHostingView.__deallocating_deinit → -[UIView dealloc] → UICorePlatformViewHost.removeFromSuperview() → willMoveToParentViewController:
The store controller is being torn down, not presented, when it throws. A SwiftUI hosting view is deallocating; UIKit's UICorePlatformViewHost (SwiftUI's UIKit view host — the thing that exists when a UIKit view/controller is embedded through a UIViewRepresentable / UIViewControllerRepresentable, not when a controller is present(_:animated:)-ed) tears down its hierarchy and re-parents the store controller to nil. StoreKit sees an unsupported presentation and throws.
That the throw escapes a dealloc inside an autorelease-pool drain (objc_autoreleasePoolPop → __CFRunLoopPerCalloutARPEnd) is why there is nothing to catch it and why the crashing thread carries no app frame at all: the exception surfaces at the runloop's pool boundary, far from any code that could have handled it. It is unconditionally fatal.
Where this is in the source
AuthAppForTesla/View/About/AboutViewFriend.swift is the only place in the repo that touches SKStoreProductViewController (lines 49–64), and it is the "friend apps" grid on the About tab — which matches every tester comment on this cluster. Its history is directly relevant:
47096fc (8 Mar 2026, "Fix friend app crash and login black screen") — removed SKStoreProductViewController entirely, with the commit message "crashes on dismiss in SwiftUI sheet", replacing it with openURL to apps.apple.com. That is this exact bug, already diagnosed once.
ae4086e (8 Mar 2026, 43 seconds later, "Restore in-app App Store overlay for friend apps") — put it back, now presented imperatively via topVC.present(storeVC, animated: true), on the grounds that this "resolves the crash while keeping the in-app product page experience".
The UICorePlatformViewHost frame says the build that crashed still had the store controller living inside a SwiftUI-hosted view hierarchy, i.e. the pre-47096fc StoreProductView representable-in-a-sheet. TestFlight did not record a commit for these builds (they were not from Xcode Cloud) and the build number is not in project.pbxproj, so the mapping from build 53/56 to a commit cannot be proven from this repo — but the stack shape is the pre-ae4086e code, not the current one.
That does not make the current code safe. The presentStoreProduct(appID:) that is on main today still has two problems that _configureForFullScreenPresentationOrThrowException can fire on:
- It walks
presentedViewController to the topmost controller and presents there. In a SwiftUI app that top controller is typically a UIHostingController owned by a .sheet; when SwiftUI tears that sheet down it can deallocate the host out from under the store controller — the same ownership problem, reached by a different route.
topVC.present(storeVC, animated: true) uses the ambient modalPresentationStyle. Nothing sets .fullScreen, so an inherited .formSheet/.popover (or an iPad presentation context) is exactly the "unsupported presentation" the assertion rejects.
Suggested fix
- Present from the window scene's root view controller, not the topmost presented one.
- Set
storeVC.modalPresentationStyle = .fullScreen explicitly before presenting.
- Set
storeVC.delegate and dismiss through productViewControllerDidFinish(_:), holding a strong reference for its lifetime, so SwiftUI never owns its teardown.
- Or take
47096fc's route and just openURL the apps.apple.com link — the in-app product page is a nicety, and this bug has now cost four crash reports.
Related
All four AuthAppForTesla TestFlight reports in this batch are the same defect — the friend-app SKStoreProductViewController presentation in AboutViewFriend.swift. The three build-53 reports have byte-identical exception paths; the build-56 report has no log but says "Still crashes".
This report ("Tapped a friend") is the first of the four and names the trigger most clearly: tapping a friend app in the About tab's friend grid.
Written by Claude (Opus 5) working in Kim's session — posted under his account because that is the only token available. Anything in this tracker without this footer was written by Kim himself.
TestFlight feedback — crash · 2026-03-09T17:18:53.466Z
Tester comment
Build context
Device
Crash signature
EXC_CRASH (SIGABRT)0x0000000000000000, 0x0000000000000000SIGNAL 6 Abort trap: 6The crashing thread is only the abort machinery — an uncaught Objective-C exception unwinding out of the main runloop:
The real call site is in the
Last Exception Backtrace, and it is fully symbolicated:Analysis
The thrown exception is StoreKit's own, and it names its own reason:
-[SKStoreProductViewController _throwUnsupportedPresentationException], reached from_configureForFullScreenPresentationOrThrowException.SKStoreProductViewControllerrefuses to be anything but a full-screen modal — it must not be embedded as a child view controller or re-parented — and it enforces that by raisingNSExceptionfromwillMoveToParentViewController:.Read the frames below the throw and the timing is the whole story:
_UIHostingView.__deallocating_deinit→-[UIView dealloc]→UICorePlatformViewHost.removeFromSuperview()→willMoveToParentViewController:The store controller is being torn down, not presented, when it throws. A SwiftUI hosting view is deallocating; UIKit's
UICorePlatformViewHost(SwiftUI's UIKit view host — the thing that exists when a UIKit view/controller is embedded through aUIViewRepresentable/UIViewControllerRepresentable, not when a controller ispresent(_:animated:)-ed) tears down its hierarchy and re-parents the store controller tonil. StoreKit sees an unsupported presentation and throws.That the throw escapes a
deallocinside an autorelease-pool drain (objc_autoreleasePoolPop→__CFRunLoopPerCalloutARPEnd) is why there is nothing to catch it and why the crashing thread carries no app frame at all: the exception surfaces at the runloop's pool boundary, far from any code that could have handled it. It is unconditionally fatal.Where this is in the source
AuthAppForTesla/View/About/AboutViewFriend.swiftis the only place in the repo that touchesSKStoreProductViewController(lines 49–64), and it is the "friend apps" grid on the About tab — which matches every tester comment on this cluster. Its history is directly relevant:47096fc(8 Mar 2026, "Fix friend app crash and login black screen") — removedSKStoreProductViewControllerentirely, with the commit message "crashes on dismiss in SwiftUI sheet", replacing it withopenURLtoapps.apple.com. That is this exact bug, already diagnosed once.ae4086e(8 Mar 2026, 43 seconds later, "Restore in-app App Store overlay for friend apps") — put it back, now presented imperatively viatopVC.present(storeVC, animated: true), on the grounds that this "resolves the crash while keeping the in-app product page experience".The
UICorePlatformViewHostframe says the build that crashed still had the store controller living inside a SwiftUI-hosted view hierarchy, i.e. the pre-47096fcStoreProductViewrepresentable-in-a-sheet. TestFlight did not record a commit for these builds (they were not from Xcode Cloud) and the build number is not inproject.pbxproj, so the mapping from build 53/56 to a commit cannot be proven from this repo — but the stack shape is the pre-ae4086ecode, not the current one.That does not make the current code safe. The
presentStoreProduct(appID:)that is onmaintoday still has two problems that_configureForFullScreenPresentationOrThrowExceptioncan fire on:presentedViewControllerto the topmost controller and presents there. In a SwiftUI app that top controller is typically aUIHostingControllerowned by a.sheet; when SwiftUI tears that sheet down it can deallocate the host out from under the store controller — the same ownership problem, reached by a different route.topVC.present(storeVC, animated: true)uses the ambientmodalPresentationStyle. Nothing sets.fullScreen, so an inherited.formSheet/.popover(or an iPad presentation context) is exactly the "unsupported presentation" the assertion rejects.Suggested fix
storeVC.modalPresentationStyle = .fullScreenexplicitly before presenting.storeVC.delegateand dismiss throughproductViewControllerDidFinish(_:), holding a strong reference for its lifetime, so SwiftUI never owns its teardown.47096fc's route and justopenURLtheapps.apple.comlink — the in-app product page is a nicety, and this bug has now cost four crash reports.Related
All four AuthAppForTesla TestFlight reports in this batch are the same defect — the friend-app
SKStoreProductViewControllerpresentation inAboutViewFriend.swift. The three build-53 reports have byte-identical exception paths; the build-56 report has no log but says "Still crashes".This report ("Tapped a friend") is the first of the four and names the trigger most clearly: tapping a friend app in the About tab's friend grid.
Written by Claude (Opus 5) working in Kim's session — posted under his account because that is the only token available. Anything in this tracker without this footer was written by Kim himself.