cefsharp/CefSharp · error · Exception

Frame is invalid, unable to continue.

Error message

Frame is invalid, unable to continue.

What it means

Thrown by the DownloadUrl extension method when frame.IsValid is false. A frame becomes invalid after navigation, frame detach, or browser disposal — CEF has already torn down the underlying CefFrame handle. The method cannot create a request on a dead frame, so it refuses immediately rather than silently failing on the CEF UI thread.

Source

Thrown at CefSharp.Core/WebBrowserExtensionsEx.cs:65

                tcs.TrySetResult(entry);
            });

            return tcs.Task;
        }

        /// <summary>
        /// Downloads the specified <paramref name="url"/> and calls <paramref name="completeHandler"/>
        /// when the download is complete. Makes a GET Request.
        /// </summary>
        /// <param name="frame">valid frame</param>
        /// <param name="url">url to download</param>
        /// <param name="completeHandler">Action to be executed when the download is complete.</param>
        public static void DownloadUrl(this IFrame frame, string url, Action<IUrlRequest, Stream>  completeHandler)
        {
            if (!frame.IsValid)
            {
                throw new Exception("Frame is invalid, unable to continue.");
            }

            //Can be created on any valid CEF Thread, here we'll use the CEF UI Thread
            Cef.UIThreadTaskFactory.StartNew(delegate
            {
                var request = frame.CreateRequest(false);

                request.Method = "GET";
                request.Url = url;

                var memoryStream = new MemoryStream();

                var urlRequestClient = Fluent.UrlRequestClient
                    .Create()
                    .OnDownloadData((req, stream) =>
                    {
                        stream.CopyTo(memoryStream);
                    })

View on GitHub (pinned to 16bc6e0711)

Solutions

  1. Check frame.IsValid immediately before calling DownloadUrl and skip if false.
  2. Reacquire the frame from browser.MainFrame at the call site rather than caching it long-term.
  3. Move the download trigger into a lifecycle-safe handler (e.g. LoadingStateChanged with the current frame captured at call time).

Example fix

// before
frame.DownloadUrl(url, OnComplete);

// after
if (frame.IsValid)
{
    frame.DownloadUrl(url, OnComplete);
}
Defensive patterns

Strategy: validation

Validate before calling

if (frame == null || !frame.IsValid) return;
frame.DownloadUrl(url, handler);

Type guard

public static bool IsFrameUsable(IFrame f) => f != null && f.IsValid;

Try / catch

try { frame.DownloadUrl(url, handler); }
catch (Exception ex) when (ex.Message.Contains("Frame is invalid")) { /* re-fetch frame or skip */ }

Prevention

When it happens

Trigger: Calling frame.DownloadUrl(url, handler) after the page navigated away, after the frame was removed from the DOM, or after the browser was disposed. Common in FrameLoadStart/FrameLoadEnd racing or in async callbacks that outlive the frame.

Common situations: Storing an IFrame reference in a field and using it later in an async continuation. Handling a download triggered from a popup frame that closed. Cross-frame access after a redirect changed main frame identity.

Related errors


AI-assisted analysis of cefsharp/CefSharp@16bc6e0711 (2026-08-13). Data as JSON: /api/errors/817210aa9ce52672. Report an issue: GitHub.