dotnet/wpf · error · InvalidOperationException
SR.DispatcherHasShutdown
Error message
SR.DispatcherHasShutdown
What it means
Dispatcher.PushFrame throws InvalidOperationException with SR.DispatcherHasShutdown when the dispatcher for the current thread has already finished shutting down (_hasShutdownFinished is true). Once a Dispatcher has shut down, it can no longer process its message queue, so pushing a new nested message loop (a frame) is not allowed. WPF surfaces this as a plain InvalidOperationException with the localized message string.
Solutions
- Do not call PushFrame/Run again on a thread whose dispatcher has shut down; create a new thread (with a new Dispatcher) instead.
- Guard with Dispatcher.CurrentDispatcher.HasShutdownFinished and skip pumping when true.
- Move the work that needs pumping onto a still-running dispatcher (e.g. the Application's UI thread) via Dispatcher.Invoke/InvokeAsync.
- Fix code paths that call InvokeShutdown/BeginInvokeShutdown prematurely before all frames are done.
Example fix
// before
Dispatcher.PushFrame(new DispatcherFrame());
// after
var d = Dispatcher.CurrentDispatcher;
if (!d.HasShutdownFinished)
{
Dispatcher.PushFrame(new DispatcherFrame());
} Defensive patterns
Strategy: validation
Validate before calling
if (Dispatcher.CurrentDispatcher.HasShutdownFinished)
return; // cannot pump anymore
Dispatcher.PushFrame(new DispatcherFrame()); Type guard
static bool CanPushFrame => !Dispatcher.CurrentDispatcher.HasShutdownFinished;
Prevention
- Check HasShutdownFinished before any PushFrame/Run
- Never restart a message pump after Application shutdown completes
- Create dedicated threads (with their own Dispatcher) instead of reusing shut-down ones
- Audit InvokeShutdown/BeginInvokeShutdown call sites for premature shutdown
When it happens
Trigger: Calling Dispatcher.Run() or Dispatcher.PushFrame(new DispatcherFrame()) on a thread whose Dispatcher has already completed shutdown (e.g. after InvokeShutdown/BeginInvokeShutdown finished, or after Application exit processed). Calling PushFrame from within a shutdown-complete callback or after the message loop exited.
Common situations: Restarting a message pump on a UI thread after Application.Run returned; calling ShowDialog/PushFrame during shutdown sequences; unit tests that shut the dispatcher down then try to pump again; threads created with Run() whose Run loop returned but code keeps pumping.
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
- SR.Format(SR.AccessCollectionAfterShutDown, collection)
- Processing is disabled while the Dispatcher is in this…
- SR.AutomationDispatcherShutdown
- SR.CollectionView_MissingSynchronizationCallback
- SR.ContextMenuInDifferentDispatcher
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/263295a943cbfc18.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:304
public static void Run()
{
PushFrame(new DispatcherFrame());
}
/// <summary>
/// Push an execution frame.
/// </summary>
/// <param name="frame">
/// The frame for the dispatcher to process.
/// </param>
public static void PushFrame(DispatcherFrame frame)
{
ArgumentNullException.ThrowIfNull(frame);
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
if(dispatcher._hasShutdownFinished) // Dispatcher thread - no lock needed for read
{
throw new InvalidOperationException(SR.DispatcherHasShutdown);
}
if(frame.Dispatcher != dispatcher)
{
throw new InvalidOperationException(SR.MismatchedDispatchers);
}
if(dispatcher._disableProcessingCount > 0)
{
throw new InvalidOperationException(SR.DispatcherProcessingDisabled);
}
dispatcher.PushFrameImpl(frame);
}
/// <summary>
/// Requests that all nested frames exit.
/// </summary>View on GitHub (pinned to 81131a70a4)