dotnet/wpf · error · InvalidOperationException

SR.CompatibilityPreferencesSealed…

Error message

SR.CompatibilityPreferencesSealed (ReuseDispatcherSynchronizationContextInstance, BaseCompatibilityPreferences)

What it means

BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance can only be set before WPF seals the compatibility preferences (which happens once the Application/Dispatcher infrastructure initializes). Setting it afterwards throws InvalidOperationException with SR.CompatibilityPreferencesSealed naming this property. The setter is guarded by a lock and an _isSealed flag.

Solutions

  1. Move the assignment to the earliest point in the process, e.g. before creating the Application object (in Main or a module initializer).
  2. Ensure all BaseCompatibilityPreferences writes happen on one thread before any WPF type from PresentationFramework is touched.
  3. In tests, run each preference-setting test in its own process/appdomain, or read rather than write preferences after init.

Example fix

// before
protected override void OnStartup(StartupEventArgs e)
{
    BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance = true;
    ...
}
// after
public static void Main()
{
    BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance = true;
    var app = new App();
    app.Run();
}
Defensive patterns

Strategy: validation

Validate before calling

// Call this in Main before any WPF type is used:
void ConfigureCompatPreferences()
{
    // must be the first WPF touch point in the process
    BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance = true;
}

Try / catch

try { BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance = v; }
catch (InvalidOperationException) { /* already sealed: setting ignored — log and continue */ }

Prevention

When it happens

Trigger: Assigning BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance = true/false anywhere after the Application has been constructed or a Dispatcher has started (e.g. in App.OnStartup after base init, or on a background thread late in app lifetime).

Common situations: Moving compatibility settings out of the static Main/PreStart phase during a refactor; setting them in a unit test after a previous test already touched WPF; setting them inside event handlers.

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


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/BaseCompatibilityPreferences.cs:84

        ///
        ///     2) Some task-parallel implementations implement potentially
        ///         cross-thread completions by callling
        ///         SynchronizationContext.Post and Wait() and an event to be
        ///         signaled.  If this was not a true cross-thread completion,
        ///         but rather just two seperate instances of
        ///         DispatcherSynchronizationContext for the same thread, this
        ///         would result in a deadlock.
        /// </summary>
        public static bool ReuseDispatcherSynchronizationContextInstance
        {
            get { return _reuseDispatcherSynchronizationContextInstance; }
            set
            {
                lock (_lockObject)
                {
                    if (_isSealed)
                    {
                        throw new InvalidOperationException(SR.Format(SR.CompatibilityPreferencesSealed, "ReuseDispatcherSynchronizationContextInstance", "BaseCompatibilityPreferences"));
                    }

                    _reuseDispatcherSynchronizationContextInstance = value;
                }
            }
        }

        internal static bool GetReuseDispatcherSynchronizationContextInstance()
        {
            Seal();

            return ReuseDispatcherSynchronizationContextInstance;
        }

#if NETFX && !NETCOREAPP
        private static bool _reuseDispatcherSynchronizationContextInstance = BinaryCompatibility.TargetsAtLeast_Desktop_V4_5 ? false : true;
#elif NETCOREAPP
        private static bool _reuseDispatcherSynchronizationContextInstance = false;

View on GitHub (pinned to 81131a70a4)