dotnet/wpf · error · InvalidOperationException
Processing is disabled while the Dispatcher is in this…
Error message
Processing is disabled while the Dispatcher is in this state.
What it means
WPF's Dispatcher prohibits re-entrant message processing while processing is disabled (when _disableProcessingCount > 0, set via Dispatcher.DisableProcessing). If a window message arrives and the WndProcHook is entered while processing is disabled, the Dispatcher throws InvalidOperationException because pumping messages in a disabled state would violate its reentrancy guarantees.
Solutions
- Remove the surrounding DisableProcessing/EnableProcessing scope before any call that can pump messages
- Ensure DisableProcessing is only used for short, non-pumping critical sections
- Use Dispatcher.PushFrame-free alternatives (e.g. async/await) instead of blocking waits inside disabled regions
- Wrap the region in try/finally so EnableProcessing is always called and the count does not leak
Example fix
// before
using (Dispatcher.CurrentDispatcher.DisableProcessing())
{
MessageBox.Show("done"); // pumps messages -> throws
}
// after
MessageBox.Show("done");
using (Dispatcher.CurrentDispatcher.DisableProcessing())
{
DoCriticalWork();
} Defensive patterns
Strategy: try-catch
Validate before calling
// Only pump-free work inside disabled regions bool safe = Dispatcher.CurrentDispatcher.DisableProcessingCountIsZero(); // custom check via reflection if needed
Try / catch
try
{
workThatMayPump();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Processing is disabled"))
{
logger.LogWarning("Attempted message pumping while dispatcher processing disabled");
} Prevention
- Never show modal dialogs or block-wait inside DisableProcessing scopes
- Keep disabled regions short and pump-free
- Always EnableProcessing in finally
- Prefer async/await over reentrancy suppression
When it happens
Trigger: Calling Dispatcher.DisableProcessing() and then performing an operation that pumps messages (e.g. showing a modal dialog, waiting on a dispatcher operation) so WndProcHook receives a message while _disableProcessingCount > 0.
Common situations: Developers disabling dispatcher processing to block background reentrancy but then calling APIs that implicitly pump messages (MessageBox, drag-drop, Wait on a DispatcherOperation) on the dispatcher thread.
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.DispatcherProcessingDisabled
- SR.CollectionView_MissingSynchronizationCallback
- SR.ContextMenuInDifferentDispatcher
- SR.CurrentDispatcherNotFound
- SR.DispatcherHasShutdown
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9186f2dc11bc7fcb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Threading/Dispatcher.cs:2213
private void TranslateAndDispatchMessage(ref MSG msg)
{
bool handled = false;
handled = ComponentDispatcher.RaiseThreadMessage(ref msg);
if(!handled)
{
UnsafeNativeMethods.TranslateMessage(ref msg);
UnsafeNativeMethods.DispatchMessage(ref msg);
}
}
private IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
WindowMessage message = (WindowMessage)msg;
if(_disableProcessingCount > 0)
{
throw new InvalidOperationException(SR.DispatcherProcessingDisabledButStillPumping);
}
if(message == WindowMessage.WM_DESTROY)
{
if(!_hasShutdownStarted && !_hasShutdownFinished) // Dispatcher thread - no lock needed for read
{
// Aack! We are being torn down rudely! Try to
// shut the dispatcher down as nicely as we can.
ShutdownImpl();
}
}
else if(message == _msgProcessQueue)
{
ProcessQueue();
}
else if(message == WindowMessage.WM_TIMER && (int) wParam == TIMERID_BACKGROUND)
{
// This timer is just used to process background operations.View on GitHub (pinned to 81131a70a4)