dotnet/wpf · error · System.InvalidOperationException
SR.Verify_ApartmentState (template: Verify_ApartmentState…
Error message
SR.Verify_ApartmentState (template: Verify_ApartmentState, arg: requiredState)
What it means
Verify.IsApartmentState asserts that the calling thread's COM apartment state (STA/MTA/Unknown) matches the state required by the API being called. WindowsBase throws InvalidOperationException because apartment affinity is a caller/threading contract, not an argument problem: the operation simply cannot run on a thread with the wrong apartment state. This is used by WPF APIs that require an STA thread (e.g. for UI or clipboard/ Freezable work).
Solutions
- Before starting the thread, set Thread.CurrentThread.SetApartmentState(ApartmentState.STA) (must be called before Thread.Start()).
- Move the call onto an STA thread: new Thread(...) { SetApartmentState = ApartmentState.STA } and marshal the result back.
- If on the UI thread already, ensure the work runs via Dispatcher.Invoke/BeginInvoke on the STA UI dispatcher instead of a worker thread.
- For Task-based code, use a dedicated STA scheduler/Thread rather than Task.Run (ThreadPool threads are MTA).
Example fix
// before Task.Run(() => CreateVisual()); // MTA thread -> InvalidOperationException // after var t = new Thread(() => CreateVisual()); t.SetApartmentState(ApartmentState.STA); t.Start();
Defensive patterns
Strategy: validation
Validate before calling
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
throw new InvalidOperationException("This API requires an STA thread. Use SetApartmentState(ApartmentState.STA) before Thread.Start(), or dispatch to the UI thread."); Type guard
bool IsStaThread() => Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;
Try / catch
try
{
CallStaOnlyApi();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("ApartmentState"))
{
RunOnStaThread(() => CallStaOnlyApi());
} Prevention
- Always call thread.SetApartmentState(ApartmentState.STA) before Thread.Start() for WPF/COM work
- Never call STA-only WPF APIs from Task.Run; use Dispatcher.Invoke or a dedicated STA thread
- For services/console apps, mark main or the worker thread STA explicitly
- Centralize STA-thread creation in a helper so ad-hoc threads can't forget it
When it happens
Trigger: Calling an API that wraps Verify.IsApartmentState(ApartmentState.STA) (or a specific requiredState) from a thread whose Thread.GetApartmentState() differs - e.g. calling from a plain ThreadPool/Task thread or an MTA thread when STA is required.
Common situations: Creating WPF visuals, Freezables, or using STA-only COM interop from a background Task.Run thread; spawning a Thread without SetApartmentState(ApartmentState.STA) before Start(); hosting WPF in a console/service whose main thread is MTA.
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.Format(SR.AxRequiresApartmentThread, clsid.ToString())
- SR.PTProvider_VerifyAccess
- SR.RequiresSTA
- SR.RequiresSTA
- ElementNotAvailableException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/f41f29320d137052.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/Verify.cs:31
internal static class Verify
{
/// <summary>
/// Ensure that the current thread's apartment state is what's expected.
/// </summary>
/// <param name="requiredState">
/// The required apartment state for the current thread.
/// </param>
/// <param name="message">
/// The message string for the exception to be thrown if the state is invalid.
/// </param>
/// <exception cref="InvalidOperationException">
/// Thrown if the calling thread's apartment state is not the same as the requiredState.
/// </exception>
public static void IsApartmentState(ApartmentState requiredState)
{
if (Thread.CurrentThread.GetApartmentState() != requiredState)
{
throw new InvalidOperationException(SR.Format(SR.Verify_ApartmentState, requiredState));
}
}
/// <summary>
/// Ensure that an argument is neither null nor empty.
/// </summary>
/// <param name="value">The string to validate.</param>
/// <param name="name">The name of the parameter that will be presented if an exception is thrown.</param>
public static void IsNeitherNullNorEmpty(string value, string name)
{
// catch caller errors, mixing up the parameters. Name should never be empty.
Debug.Assert(!string.IsNullOrEmpty(name));
// Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P
if (value == null)
{
throw new ArgumentNullException(name, SR.Verify_NeitherNullNorEmpty);
}View on GitHub (pinned to 81131a70a4)