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

  1. Do not call PushFrame/Run again on a thread whose dispatcher has shut down; create a new thread (with a new Dispatcher) instead.
  2. Guard with Dispatcher.CurrentDispatcher.HasShutdownFinished and skip pumping when true.
  3. Move the work that needs pumping onto a still-running dispatcher (e.g. the Application's UI thread) via Dispatcher.Invoke/InvokeAsync.
  4. 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

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


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)