dotnet/wpf · error · InvalidOperationException

SR.CompatibilityPreferencesSealed…

Error message

SR.CompatibilityPreferencesSealed (InlineDispatcherSynchronizationContextSend, BaseCompatibilityPreferences)

What it means

BaseCompatibilityPreferences.InlineDispatcherSynchronizationContextSend may only be configured before WPF seals its compatibility preferences; after sealing, the setter throws InvalidOperationException with SR.CompatibilityPreferencesSealed naming this property. Sealing occurs when the WPF runtime initializes (first Application/Dispatcher use), so late writes are rejected.

Solutions

  1. Set the property at the very start of the process (Main/module initializer) before instantiating Application.
  2. Read config synchronously before WPF initialization rather than lazily after startup.
  3. If the setting must be conditional, compute the condition pre-init, not inside WPF callbacks.

Example fix

// before
private void OnLoaded(object s, RoutedEventArgs e)
{
    BaseCompatibilityPreferences.InlineDispatcherSynchronizationContextSend = true;
}
// after
public static void Main()
{
    BaseCompatibilityPreferences.InlineDispatcherSynchronizationContextSend = true;
    new App().Run();
}
Defensive patterns

Strategy: validation

Validate before calling

// Runs only during pre-init:
static class CompatPrefs
{
    [ModuleInitializer]
    public static void Init() =>
        BaseCompatibilityPreferences.InlineDispatcherSynchronizationContextSend = true;
}

Try / catch

try { BaseCompatibilityPreferences.InlineDispatcherSynchronizationContextSend = v; }
catch (InvalidOperationException) { /* sealed — apply at next process start instead */ }

Prevention

When it happens

Trigger: Assigning BaseCompatibilityPreferences.InlineDispatcherSynchronizationContextSubtitle/InlineDispatcherSynchronizationContextSend after the Dispatcher exists — e.g. from a Dispatcher.Invoke callback, an event handler, or second app-domain initialization.

Common situations: Toggling SynchronizationContext inline-send behavior to fix async timing bugs discovered in production and placing the fix in Startup; dynamic configuration loaded from a config file read after WPF init.

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/0d9f63959180b7ef. Report an issue: GitHub.

Appendix: source

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

        ///     posts through the Dispatcher queue.
        ///
        ///     In WPF 4.5 we are changing the behavior such that calling
        ///     SynchronizationContext.Send on the same thread, will not post
        ///     through the Dispatcher queue, but rather invoke the delegate
        ///     more directly.  The cross-thread behavior does not change.
        ///
        ///     This is, of course, an observable change in behavior.
        /// </summary>
        public static bool InlineDispatcherSynchronizationContextSend
        {
            get { return _inlineDispatcherSynchronizationContextSend; }
            set
            {
                lock (_lockObject)
                {
                    if (_isSealed)
                    {
                        throw new InvalidOperationException(SR.Format(SR.CompatibilityPreferencesSealed, "InlineDispatcherSynchronizationContextSend", "BaseCompatibilityPreferences"));
                    }

                    _inlineDispatcherSynchronizationContextSend = value;
                }
            }
        }

        internal static bool GetInlineDispatcherSynchronizationContextSend()
        {
            Seal();

            return InlineDispatcherSynchronizationContextSend;
        }

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

View on GitHub (pinned to 81131a70a4)