dotnet/wpf · error · InvalidOperationException

SR.MediaContext_APINotAllowed

Error message

SR.MediaContext_APINotAllowed

What it means

MediaContext.VerifyWriteAccess throws InvalidOperationException(SR.MediaContext_APINotAllowed) when an API that mutates rendering state is called while the MediaContext is in read-only mode (WriteAccessEnabled == false). Certain APIs are forbidden in contexts like rendering during dispose or from disallowed threads/states.

Solutions

  1. Stop rendering work before shutdown: unsubscribe CompositionTarget.Rendering in Window.Closed/Unloaded.
  2. Marshal visual mutations to the UI thread via Dispatcher.Invoke/BeginInvoke with DispatcherObject checks.
  3. Guard callbacks with a disposed/closing flag and bail out early when the window is closing.
  4. Delay resource-freeing work until after the render pass completes (Dispatcher.BeginInvoke at Background priority).

Example fix

// before
void OnRendering(object sender, EventArgs e) {
    if (closed) { UpdateVisual(); } // MediaContext read-only -> throws
}
// after
void OnRendering(object sender, EventArgs e) {
    if (closed) return; // or: Unsubscribe on Closed
}
private void Window_Closed(object sender, EventArgs e) {
    CompositionTarget.Rendering -= OnRendering;
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (window.IsClosed || Application.Current == null || Application.Current.Dispatcher.HasShutdownStarted) return; // skip render-callback work

Type guard

bool CanMutateVisuals(Visual v) =>
    v != null && !v.Dispatcher.HasShutdownStarted && v.Dispatcher.CheckAccess();

Try / catch

try { MutateVisual(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("not allowed")) { /* context became read-only: skip work */ }

Prevention

When it happens

Trigger: Calling a rendering API guarded by VerifyWriteAccess (e.g., modifying visuals or subscribing to rendering during teardown) after the MediaContext went read-only — commonly during window close / application shutdown while render callbacks still fire.

Common situations: CompositionTarget.Rendering handlers touching visuals after the host window is closed; background threads mutating visuals without Dispatcher dispatch; work scheduled in finalizers/shutdown hooks.

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/8fe2fe54853632cc. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContext.cs:2298

        /// <summary>
        /// This function is registered with the MediaContext's TimeManager. It is called whenever
        /// a clock managed by the TimeManager goes active, but only if there hasn't been already an
        /// active clock. For now we start the animation thread in there.
        /// </summary>
        private void OnNeedTickSooner(object sender, EventArgs e)
        {
            PostRender();
        }

        /// <summary>
        /// Checks if the current context can request the specified permissions.
        /// </summary>
        internal void VerifyWriteAccess()
        {
            if (!WriteAccessEnabled)
            {
                throw new InvalidOperationException(SR.MediaContext_APINotAllowed);
            }
        }

        /// <summary>
        /// Returns false if the MediaContext is currently read-only
        /// </summary>
        internal bool WriteAccessEnabled
        {
            get { return _readOnlyAccessCounter <= 0; }
        }

        /// <summary>
        /// Methods to lock down the Visual tree for write access.
        /// </summary>
        internal void PushReadOnlyAccess()
        {
            _readOnlyAccessCounter++;
        }

View on GitHub (pinned to 81131a70a4)