stride3d/stride · error · InvalidOperationException

An error occurred while disposing the window manager.

Error message

An error occurred while disposing the window manager.

What it means

Dispose unhooks the native WinEvent hook via NativeHelper.UnhookWinEvent. If the unhook call returns false, cleanup failed and the method throws InvalidOperationException so callers know the manager was not fully torn down and native resources may still be hooked.

Solutions

  1. Dispose on the same thread that constructed the WindowManager (the dispatcher thread)
  2. Ensure Dispose is called exactly once (guard with a disposed flag or use try/finally)
  3. If unhook fails on shutdown, log and continue — wrap Dispose in try/catch since the process is tearing down anyway

Example fix

// before
manager.Dispose(); manager.Dispose(); // second call: hook already zeroed/invalid
// after
if (manager != null) { manager.Dispose(); manager = null; }
Defensive patterns

Strategy: try-catch

Validate before calling

if (manager == null || manager.IsDisposed) return;

Try / catch

try { manager.Dispose(); } catch (InvalidOperationException ex) when (ex.Message.Contains("disposing the window manager")) { /* log; shutdown race */ }

Prevention

When it happens

Trigger: Calling Dispose after the hook was already invalidated or the native unhook failed (invalid hook handle, wrong thread context, or double-dispose scenarios where the handle is stale).

Common situations: Disposing from a different thread/context than the hook was installed on; double disposal or disposing after hook corruption; native layer returning failure under shutdown races.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/af3dd070d874b21b. Report an issue: GitHub.

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Windows/WindowManager.cs:77

        /// Gets the current main window.
        /// </summary>
        public static WindowInfo MainWindow { get; private set; }

        /// <summary>
        /// Gets the collection of currently visible modal windows.
        /// </summary>
        public static IReadOnlyList<WindowInfo> ModalWindows => ModalWindowsList;

        /// <summary>
        /// Gets the collection of currently visible blocking windows.
        /// </summary>
        public static IReadOnlyList<WindowInfo> BlockingWindows => BlockingWindowsList;

        /// <inheritdoc/>
        public void Dispose()
        {
            if (!NativeHelper.UnhookWinEvent(hook))
                throw new InvalidOperationException("An error occurred while disposing the window manager.");

            hook = IntPtr.Zero;
            winEventProc = null;
            dispatcher = null;
            MainWindow = null;
            AllWindowsList.Clear();
            ModalWindowsList.Clear();
            BlockingWindowsList.Clear();

            Logger.Info($"{nameof(WindowManager)} disposed");
            initialized = false;
        }

        /// <summary>
        /// Shows the given window as the main window of the application. It is mandatory to use this method for the main window to use features of the <see cref="WindowManager"/>.
        /// </summary>
        /// <param name="window">The main window to show.</param>
        public static void ShowMainWindow([NotNull] Window window)

View on GitHub (pinned to 96fad776d2)