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

  1. Mark the main entry point with [STAThread] attribute.
  2. On manually created threads, call thread.SetApartmentState(ApartmentState.STA) before thread.Start().
  3. Marshal all UI/input object creation onto the existing STA UI thread via Dispatcher.Invoke/InvokeAsync.
  4. 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

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


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)