dotnet/wpf · critical · InvalidOperationException
SR.RequiresSTA
Error message
SR.RequiresSTA
What it means
The InputManager constructor throws InvalidOperationException(SR.RequiresSTA) when constructed on a thread whose apartment state is not STA. WPF input relies heavily on STA-only components (Cicero/TSF, OLE, COM). InputManager is created implicitly by UI infrastructure, so this fires when a control or input-related object is first touched on an MTA or background thread.
Solutions
- Mark the main entry point with [STAThread] attribute.
- On manually created threads, call thread.SetApartmentState(ApartmentState.STA) before thread.Start().
- Marshal all UI/input object creation onto the existing STA UI thread via Dispatcher.Invoke/InvokeAsync.
- Never create WPF visual/input objects inside Task.Run or ThreadPool work items.
Example fix
// before var t = new Thread(() => new Window().Show()); t.Start(); // after var t = new Thread(() => new Window().Show()); t.SetApartmentState(ApartmentState.STA); t.Start();
Defensive patterns
Strategy: validation
Validate before calling
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
throw new InvalidOperationException("UI creation requires an STA thread"); Type guard
static bool IsStaThread() => Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;
Try / catch
try { CreateUiOnThisThread(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("STA"))
{ Dispatcher.CurrentDispatcher.Invoke(CreateUiOnThisThread); } Prevention
- Always annotate Main with [STAThread] in WPF applications.
- Call SetApartmentState(ApartmentState.STA) on any thread that touches WPF objects.
- Never construct WPF visuals inside Task.Run or thread-pool continuations; use Dispatcher.Invoke.
When it happens
Trigger: Creating a UIElement, Dispatcher-operated input object, or instantiating InputManager directly on a thread started without SetApartmentState(ApartmentState.STA), e.g. a plain ThreadPool or Task thread.
Common situations: Creating WPF controls on background threads; running UI code in console apps or services without [STAThread]; unit test runners that use MTA threads; migrating WinForms interop code to async continuation threads.
Related errors
- SR.Format(SR.AxRequiresApartmentThread, clsid.ToString())
- SR.PTProvider_VerifyAccess
- SR.RequiresSTA
- SR.Verify_ApartmentState (template: Verify_ApartmentState…
- 0x80004002
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/3ca93a99d367893d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputManager.cs:144
if (inputManager == null)
{
inputManager = new InputManager();
dispatcher.InputManager = inputManager;
}
return inputManager;
}
private InputManager()
{
// STA Requirement
//
// Avalon doesn't necessarily require STA, but many components do. Examples
// include Cicero, OLE, COM, etc. So we throw an exception here if the
// thread is not STA.
if(Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
{
throw new InvalidOperationException(SR.RequiresSTA);
}
_stagingArea = new Stack();
_primaryKeyboardDevice = new Win32KeyboardDevice(this);
_primaryMouseDevice = new Win32MouseDevice(this);
_primaryCommandDevice = new CommandDevice(this);
_continueProcessingStagingAreaCallback = new DispatcherOperationCallback(ContinueProcessingStagingArea);
_hitTestInvalidatedAsyncOperation = null;
_hitTestInvalidatedAsyncCallback = new DispatcherOperationCallback(HitTestInvalidatedAsyncCallback);
_layoutUpdatedCallback = new EventHandler(OnLayoutUpdated); //need to cache it, LM only keeps weak ref
ContextLayoutManager.From(Dispatcher).LayoutEvents.Add(_layoutUpdatedCallback);
// Timer used to synchronize the input devices periodically
_inputTimer = new DispatcherTimer(DispatcherPriority.Background);View on GitHub (pinned to 81131a70a4)