Perry version: 0.5.1161 (iOS, device on iOS 26.x)
Summary
Mutating the widget tree (calling the app's rebuild() that clears+rebuilds the root container) while a system modal is presented — StoreKit's purchase sheet (Product.purchase()) or GoogleSignIn's ASWebAuthenticationSession — either segfaults or leaves the app's root window detached (white, frozen, even subsequent rebuilds don't recover) on iOS 26.
This is the same hazard class the button path already documents/avoids for touch processing:
// crates/perry-ui-ios/src/widgets/button.rs
// "Dispatch async to avoid modifying the view hierarchy during UIKit touch
// event processing (crashes on iOS 26+)."
…but it also applies to presented modals, not just touch dispatch.
Repro (in-app)
- Tap a button whose handler sets some state and calls
triggerRebuild(), then awaits a StoreKit purchase or GoogleSignIn flow (which presents a system sheet). The scheduled rebuild fires (via the heartbeat) while the sheet is up.
- Result: SIGSEGV (StoreKit sheet) or a white/frozen window after the sheet dismisses (ASWebAuthenticationSession). The process stays alive in the white case; the Perry window/root view is detached and no rebuild restores it.
We hit this three times (purchase → SIGSEGV; restore + Google-link → white/frozen). Workaround: do not rebuild between initiating the flow and awaiting it (only rebuild after the sheet dismisses).
Ask
Either document this hazard in the perry/ui guidance, or make rebuild()/root-container mutation resilient to running while a modal is presented (e.g., defer root replacement until no presentedViewController, or re-make-key-and-visible after a presented controller dismisses). The "white + frozen, unrecoverable by rebuild" case (after ASWebAuthenticationSession) is the most serious — the root window never comes back.
Perry version: 0.5.1161 (iOS, device on iOS 26.x)
Summary
Mutating the widget tree (calling the app's
rebuild()that clears+rebuilds the root container) while a system modal is presented — StoreKit's purchase sheet (Product.purchase()) or GoogleSignIn'sASWebAuthenticationSession— either segfaults or leaves the app's root window detached (white, frozen, even subsequent rebuilds don't recover) on iOS 26.This is the same hazard class the button path already documents/avoids for touch processing:
…but it also applies to presented modals, not just touch dispatch.
Repro (in-app)
triggerRebuild(), thenawaits a StoreKit purchase or GoogleSignIn flow (which presents a system sheet). The scheduled rebuild fires (via the heartbeat) while the sheet is up.We hit this three times (purchase → SIGSEGV; restore + Google-link → white/frozen). Workaround: do not rebuild between initiating the flow and awaiting it (only rebuild after the sheet dismisses).
Ask
Either document this hazard in the perry/ui guidance, or make
rebuild()/root-container mutation resilient to running while a modal is presented (e.g., defer root replacement until nopresentedViewController, or re-make-key-and-visible after a presented controller dismisses). The "white + frozen, unrecoverable by rebuild" case (after ASWebAuthenticationSession) is the most serious — the root window never comes back.