Skip to content

[QuickAccess] Suppress unhandled XAML exceptions in flyout host#48457

Open
crutkas wants to merge 2 commits into
microsoft:mainfrom
crutkas:user/crutkas/fix-quickaccess-stowed-exception
Open

[QuickAccess] Suppress unhandled XAML exceptions in flyout host#48457
crutkas wants to merge 2 commits into
microsoft:mainfrom
crutkas:user/crutkas/fix-quickaccess-stowed-exception

Conversation

@crutkas

@crutkas crutkas commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

Adds the two missing top-level exception handlers in the QuickAccess (Preview) flyout host so that an unhandled XAML exception during launch or page navigation no longer FailFasts PowerToys.QuickAccess.exe.

Spotted while reading through App.OnLaunched and ShellPage for an unrelated review of the flyout startup path — none of the existing handlers exist yet, so any throw during MainWindow construction, ShellHost.Initialize, or ContentFrame.Navigate(typeof(LaunchPage) | typeof(AppsListPage), …) bubbles all the way out to the Windows App SDK runtime and is stowed as a XAML failure. Compare with src\settings-ui\Settings.UI\SettingsXAML\App.xaml.cs, which already wires UnhandledException += App_UnhandledException.

Changes

src\settings-ui\QuickAccess.UI\QuickAccessXAML\App.xaml.cs

  • Hook Application.UnhandledException in the constructor. The handler logs the exception via ManagedCommon.Logger.LogError (same logger Settings uses) and sets e.Handled = true. QuickAccess is a transient launcher flyout owned by the runner, so swallowing a stray XAML error and keeping the host alive for the next summon is the correct trade-off — the failure is still recorded for diagnostics.
  • Wrap the body of OnLaunched in a try/catch. If MainWindow (which sets up window chrome, listener threads, the IPC coordinator, and the XAML shell) fails to construct, log the exception and call Exit() cleanly rather than letting the throw escape into the Windows App SDK launch path.

src\settings-ui\QuickAccess.UI\QuickAccessXAML\Flyout\ShellPage.xaml.cs

  • Subscribe to ContentFrame.NavigationFailed after InitializeComponent. A page constructor or XAML-load failure in LaunchPage / AppsListPage would otherwise bubble out of the Frame and crash the launcher. The handler logs the failure (SourcePageType.FullName + the exception) and marks it handled so the next summon retries navigation.

No production behaviour changes when things work — only the failure paths are different. No public API surface changes.

Why both handlers, not just one

  • Application.UnhandledException does not fire for Frame.NavigationFailed. The Frame raises its own event first and, if no handler runs or e.Handled is left false, then it rethrows on the dispatcher.
  • Conversely, Frame.NavigationFailed only fires for navigation failures — not for an exception thrown directly in OnLaunched before any navigation happens.

The two events are complementary, so both need a handler to fully cover the launch + navigation paths.

Testing

  • The local NuGet feed on my dev box currently can't restore Microsoft.NETCore.App.Runtime.win-x64 = 10.0.9 (the feed only has 11.0.0-preview.1.26104.118), which fails the project restore for every WinUI project including this one. That's the same environment issue I called out on [Settings] Add navigation smoke test using winapp CLI (no WinAppDriver) #48414 — pipeline restore uses a different feed and is fine.
  • All three patterns added here are copy-paste analogues of code that already exists in Settings.UI (App.xaml.cs:96, 106-109, ShellViewModel.cs:86, 136), so namespace and signature drift risk is minimal. The only behavioural difference is e.Handled = true, which is the actual goal of this PR.

Risk

  • Low. Two new event handlers and one try/catch. No behaviour change on the success path.
  • Worst-case regression is that a real, repeatable XAML failure becomes silent in the runner's eyes (no process crash) instead of loud — but it's logged via Logger.LogError so the user can still find the trace in %LOCALAPPDATA%\Microsoft\PowerToys\Logs\.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com


ADO: https://microsoft.visualstudio.com/DefaultCollection/OS/_workitems/edit/61258633/

crutkas and others added 2 commits June 10, 2026 12:59
PowerToys.QuickAccess.exe has no Application.UnhandledException handler and no Frame.NavigationFailed handler, so any throw during MainWindow construction or page navigation bubbles into the Windows App SDK launch path and FailFasts the process.

- App.xaml.cs: hook Application.UnhandledException (log + set Handled=true) and wrap OnLaunched in a try/catch that logs the failure and calls Exit() if MainWindow cannot be constructed.

- ShellPage.xaml.cs: hook ContentFrame.NavigationFailed (log + set Handled=true) so a LaunchPage or AppsListPage constructor failure no longer takes down the launcher.

Both patterns mirror the existing Settings.UI handlers (App.xaml.cs:96, ShellViewModel.cs:86) and use the same ManagedCommon.Logger sink.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CS0104 ambiguity between Microsoft.UI.Xaml.UnhandledExceptionEventArgs and System.UnhandledExceptionEventArgs (both in scope via the using directives). Matches the Settings.UI App.xaml.cs:106 convention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@crutkas crutkas added Needs-Review This Pull Request awaits the review of a maintainer. bug Something isn't working labels Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working Needs-Review This Pull Request awaits the review of a maintainer.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant