dotnet/wpf · error · InvalidOperationException

SR.RequiresSTA

Error message

SR.RequiresSTA

What it means

A BitmapEffect (or derived effect) was constructed on a thread whose apartment state is not STA. WPF effects rely on STA-only components (Cicero, OLE, COM), so the constructor VerifyRequiresSTA path throws InvalidOperationException with SR.RequiresSTA when Thread.CurrentThread.GetApartmentState() != ApartmentState.STA.

Solutions

  1. Create and use the effect on the WPF UI (STA) thread, e.g. via Dispatcher.Invoke
  2. Mark the entry point with [STAThread] or start the thread with Thread.SetApartmentState(ApartmentState.STA)
  3. Pre-render into a static image/source on the STA thread, then consume the result on the worker thread
  4. Migrate to the modern Effect (shader) API, which does not carry the same STA requirement

Example fix

// before
Task.Run(() => new DropShadowBitmapEffect()); // MTA thread, throws

// after
Application.Current.Dispatcher.Invoke(() =>
{
    var effect = new DropShadowBitmapEffect(); // STA UI thread
});
Defensive patterns

Strategy: try-catch

Validate before calling

static bool CanCreateBitmapEffect() =>
    Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;

Try / catch

try { var effect = new DropShadowBitmapEffect(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("STA"))
{
    // retry on the STA UI thread via Dispatcher.Invoke
}

Prevention

When it happens

Trigger: new SomeBitmapEffect() on a background/MTA thread; creating effects inside Task.Run or a non-STA worker; console/service hosts without [STAThread] on Main.

Common situations: Unit test runners with MTA threads; headless image processing services creating WPF visuals off-thread; migrating legacy code to async workers; missing [STAThread] attribute after host change.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/bde07146e2715d47. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Effects/BitmapEffect.cs:28

    /// <summary>
    /// BitmapEffect
    /// </summary>
    public abstract partial class BitmapEffect
    {
        #region Constructors
        /// <summary>
        /// Constructor
        /// </summary>
        protected BitmapEffect()
        {     
            // 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);
            }
        }

        #endregion

        #region Protected Methods
        /// <summary>
        /// This method is called before calling GetOutput on an effect.
        /// It gives a chance for the managed effect to update the properties
        /// of the unmanaged object.
        /// </summary>
        [Obsolete(MS.Internal.Media.VisualTreeUtils.BitmapEffectObsoleteMessage)]
        protected abstract void UpdateUnmanagedPropertyState(SafeHandle unmanagedEffect);


        /// <summary>
        /// Returns a safe handle to an unmanaged effect clone
        /// </summary>

View on GitHub (pinned to 81131a70a4)