Alert Closures Not Firing + Navigation Animations Broken

Hi, I hope you are doing well. We have been running up against an issue in our application which despite our best efforts we cannot seem to solve. After a certain point of use (of which we cannot seem to isolate a trigger), something internally with the way SwiftUI handles animation transactions seems to be breaking. This results in the following behavior that we (and our users) are noticing:

  1. Alerts/Sheets/NavigationPath changes lose all animations
  2. Closures associated with buttons no longer fire at all. The alert disappears, but with no animation and any action associated with the button selected does nothing. This results in an infinite loop of triggering an alert, clicking on an alert action, and the alert dismissing without the corresponding action ever occurring.

We have tried moving the navigationPath out of a view model (Observable) and into a @State variable on the view in case it was an issue with view pre-rendering due to path changes, but this did not improve our case. We hoisted the state and the alert presentation out of all subviews and onto the root view of our navigation destination (as this happens on a sub-page of the application) as well, and while did this seem to minimize occurrences it did not fully resolve it.

The app structure of our watch app is as follows:

We have a NavigationStack at the root level which wraps a TabView, containing 3 pages. Selecting a button triggers a navigation destination, presenting a detail view. The detail view is a ZStack which switches on a property contained in an @State Observable view model scoped to the detail view. The ZStack can contain one of 5 subviews, derived from a viewState enum with associated values (all of which are equatable, and by extension viewState is also an equatable type as well). One of the subviews receives a binding, which on button trigger updates the binding and thus the view containing the ZStack presents the alert. Sometimes, when this happens, the animations break, and then are subsequently broken for the remainder of the lifetime of the app until it is force-closed (not backgrounded, but a full force-close).

NavigationStack { TabView { Tab1 Tab2 // triggers navigationDestination Tab3 } .navigationDestination(for:) { DestinationView() // the view containing the ZStack + Alert } }

STEPS TO REPRODUCE Unfortunately we have not been able to ascertain exactly what is causing this issue as we cannot reproduce it in a sandbox environment, only when moving through the view flow associated with our code.

Any debugging ideas or recommendations would be greatly appreciated, as we have already tried _printChanges and do not notice any erroneous view redraws.

@astro-spacecadet, did you ever find a workaround or file a Feedback for this? If you have an FB number, I'd like to reference it in mine.

I'm hitting exactly this in a production watchOS app (Apple Watch Ultra 3, watchOS 26.6): alerts present and dismiss normally on tap, but their button closures never execute - combined with every screen-transition animation going dead (pushed views snap into place, the nav-bar clock gets stuck mid-transition position). One difference from your case: mine heals on a true scene .background transition (crown press), no force-quit needed. With an active HKWorkoutSession the app never backgrounds on its own, which is why the broken state can persist for an hour of real use.

I instrumented every alert (present / action-fired / dismiss edges) plus sheet lifecycle events, and caught a full wedged session in the field. Findings:

  • 44 consecutive alert present→dismiss cycles with zero actions fired, across 4 different alerts on 3 different presenters - including one attached directly at the NavigationStack root. So it's the scene's entire modal layer, not a particular view, binding, or spot in the hierarchy.
  • Everything else keeps working while wedged: plain Button actions (the buttons that raise the alerts demonstrably ran every time), NavigationStack pushes, onChange observers, even HealthKit hardware-button pause/resume. Only closures of buttons inside alerts are dropped.
  • Trigger correlation, likely but not deterministic: the wedged session began with a sheet dismissed programmatically (a timer clears its item binding) while the scene was .inactive - wrist down, display off. Its teardown completed ~190 ms after the binding cleared, with the scene reactivating mid-teardown - too fast for the dismissal animation to have run. A control session on the same build with the byte-identical start (same programmatic dismissal, also initiated while .inactive) stayed healthy for the whole outing - but there the animated dismissal ran fully after the scene became active again (~730 ms). So it looks like a race in the presentation layer's animation/transaction handling when a modal teardown straddles a scene-phase change, which would fit your observation that it's unreproducible on demand.

Does your flow also involve a modal being dismissed programmatically, or while the display is off? And if anyone else has hit this. I'd love to hear whether that pattern matches your case too.

Filed as FB24311744, with the full instrumented event logs of both the wedged session and the clean control attached. If anyone from the SwiftUI/watchOS team sees this: is this a known issue, and is there anything else worth capturing the next time it happens live?

Alert Closures Not Firing + Navigation Animations Broken
 
 
Q