lepoco/wpfui · error · InvalidOperationException
Unable to determine the window source.
Error message
Unable to determine the window source.
What it means
Thrown in the ObservedWindow constructor when HwndSource.FromHwnd(handle) returns null, meaning the given HWND has no associated WPF HwndSource. The class caches the source to read RootVisual and attach hooks, so without it the watcher cannot operate on that window.
Source
Thrown at src/Wpf.Ui/Appearance/ObservedWindow.cs:32
{
private readonly HwndSource _source;
/// <summary>
/// Initializes a new instance of the <see cref="ObservedWindow"/> class.
/// </summary>
/// <param name="handle">The handle of the window.</param>
/// <param name="backdrop">The backdrop type of the window.</param>
/// <param name="updateAccents">Indicates whether to update accents.</param>
public ObservedWindow(IntPtr handle, WindowBackdropType backdrop, bool updateAccents)
{
Handle = handle;
Backdrop = backdrop;
UpdateAccents = updateAccents;
HasHook = false;
HwndSource? windowSource = HwndSource.FromHwnd(handle);
_source =
windowSource ?? throw new InvalidOperationException("Unable to determine the window source.");
}
/// <summary>
/// Gets the root visual of the window.
/// </summary>
public Window? RootVisual => (Window?)_source.RootVisual;
/// <summary>
/// Gets the handle of the window.
/// </summary>
public IntPtr Handle { get; }
/// <summary>
/// Gets the backdrop type of the window.
/// </summary>
public WindowBackdropType Backdrop { get; }
/// <summary>View on GitHub (pinned to ffebacd610)
Solutions
- Only observe WPF System.Windows.Window instances and ensure they are loaded (IsLoaded true) before calling Watch/Observe so the HWND is valid.
- Prefer the Window-based overloads of SystemThemeWatcher rather than constructing ObservedWindow with a raw handle.
- If you must use a handle, confirm HwndSource.FromHwnd(handle) is non-null before constructing ObservedWindow.
Example fix
// before
var obs = new ObservedWindow(someHandle, backdrop, true);
// after
if (HwndSource.FromHwnd(someHandle) is { } src)
{
var obs = new ObservedWindow(someHandle, backdrop, true);
}
else
{
// handle is invalid or non-WPF; skip observing
} Defensive patterns
Strategy: validation
Validate before calling
if (HwndSource.FromHwnd(handle) is null) { /* skip or log; do not construct ObservedWindow */ } Type guard
static bool IsWpfHwnd(IntPtr h) => h != IntPtr.Zero && HwndSource.FromHwnd(h) is not null;
Prevention
- Prefer Window-based SystemThemeWatcher overloads instead of raw HWND construction.
- Verify the HWND belongs to a live WPF window before observing.
- Avoid observing closed/disposed or cross-process windows.
When it happens
Trigger: SystemThemeWatcher.Observe/Watch is called with an IntPtr that is zero, stale, belongs to a non-WPF window, or whose HwndSource was already disposed. FromHwnd only resolves sources created by WPF and still alive.
Common situations: Passing a handle from a WinForms or native window, calling Watch after the window has been closed/disposed, or passing IntPtr.Zero because the window was not yet realized. Cross-process handles also return null.
Related errors
- Could not get window handle.
- You cannot unwatch a window that is not yet loaded.
- Window is null
- Unable to find the base directory of the application.
- Window handle cannot be empty
AI-assisted analysis of lepoco/wpfui@ffebacd610 (2026-08-13).
Data as JSON: /api/errors/529da76f64521887.
Report an issue: GitHub.