lepoco/wpfui · error · InvalidOperationException

You cannot unwatch a window that is not yet loaded.

Error message

You cannot unwatch a window that is not yet loaded.

What it means

Thrown by SystemThemeWatcher.UnWatch when the passed window is not yet loaded. Unwatching requires the HWND to locate and detach the installed hook; an unloaded window has no handle and no hook, so the operation is invalid and explicitly rejected.

Source

Thrown at src/Wpf.Ui/Appearance/SystemThemeWatcher.cs:130

            );
            observedWindow.AddHook(WndProc);
            _observedWindows.Add(observedWindow);
        }
    }

    /// <summary>
    /// Unwatches the window and removes the hook to receive messages from the system.
    /// </summary>
    public static void UnWatch(Window? window)
    {
        if (window is null)
        {
            return;
        }

        if (!window.IsLoaded)
        {
            throw new InvalidOperationException("You cannot unwatch a window that is not yet loaded.");
        }

        IntPtr hWnd =
            (hWnd = new WindowInteropHelper(window).Handle) == IntPtr.Zero
                ? throw new InvalidOperationException("Could not get window handle.")
                : hWnd;

        ObservedWindow? observedWindow = _observedWindows.FirstOrDefault(x => x.Handle == hWnd);

        if (observedWindow is null)
        {
            return;
        }

        observedWindow.RemoveHook(WndProc);

        _ = _observedWindows.Remove(observedWindow);
    }

View on GitHub (pinned to ffebacd610)

Solutions

  1. Only call UnWatch after confirming window.IsLoaded is true.
  2. Pair Watch/UnWatch symmetrically around the Loaded/Unloaded or Shown/Closed events so the window state is consistent.
  3. Guard the call: if (!window.IsLoaded) return; before invoking UnWatch when shutdown ordering is uncertain.

Example fix

// before
SystemThemeWatcher.UnWatch(window); // window not loaded yet

// after
if (window.IsLoaded)
{
    SystemThemeWatcher.UnWatch(window);
}
Defensive patterns

Strategy: validation

Validate before calling

if (window is not null && window.IsLoaded) { SystemThemeWatcher.UnWatch(window); }

Type guard

static bool CanUnwatch(System.Windows.Window? w) => w is { IsLoaded: true };

Prevention

When it happens

Trigger: Calling SystemThemeWatcher.UnWatch(window) where window.IsLoaded is false. Common when unwatching is wired into a lifecycle event that fires before Loaded (constructor, Initialized) or after the window was never shown.

Common situations: Unsubscribing in a Closing/Unloaded handler that runs on a window that was watched but never fully loaded, or calling UnWatch defensively during shutdown on a window that was constructed but not shown.

Related errors


AI-assisted analysis of lepoco/wpfui@ffebacd610 (2026-08-13). Data as JSON: /api/errors/21066340a82ce46f. Report an issue: GitHub.