cefsharp/CefSharp · error · ObjectDisposedException

IBrowser

Error message

IBrowser

What it means

Thrown by DevToolsClient.ExecuteDevToolsMethodAsync<T> when its backing IBrowser is null or has been disposed (browser.IsDisposed is true). The client keeps a reference to the browser it was constructed with; once the browser (ChromiumWebBrowser) is disposed, any pending or new DevTools call fails fast with an ObjectDisposedException named 'IBrowser' rather than touching freed native resources.

Source

Thrown at CefSharp.Core/DevTools/DevToolsClient.cs:138

            return ExecuteDevToolsMethodAsync<DevToolsMethodResponse>(method, parameters);
        }

        /// <summary>
        /// Execute a method call over the DevTools protocol. This method can be called on any thread.
        /// See the DevTools protocol documentation at https://chromedevtools.github.io/devtools-protocol/ for details
        /// of supported methods and the expected <paramref name="parameters"/> dictionary contents.
        /// </summary>
        /// <typeparam name="T">The type into which the result will be deserialzed.</typeparam>
        /// <param name="method">is the method name</param>
        /// <param name="parameters">are the method parameters represented as a dictionary,
        /// which may be empty.</param>
        /// <returns>return a Task that can be awaited to obtain the method result</returns>
        public Task<T> ExecuteDevToolsMethodAsync<T>(string method, IDictionary<string, object> parameters = null) where T : DevToolsDomainResponseBase
        {
            if (browser == null || browser.IsDisposed)
            {
                //TODO: Queue up commands where possible
                throw new ObjectDisposedException(nameof(IBrowser));
            }

            var taskCompletionSource = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);

            var methodResultContext = new DevToolsMethodResponseContext(
                type: typeof(T),
                setResult: o => taskCompletionSource.TrySetResult((T)o),
                setException: taskCompletionSource.TrySetException,
                syncContext: CaptureSyncContext ? SynchronizationContext.Current : SyncContext
            );

            var browserHost = browser.GetHost();

            var messageId = browserHost.GetNextDevToolsMessageId();

            if (!queuedCommandResults.TryAdd(messageId, methodResultContext))
            {
                throw new DevToolsClientException(string.Format("Unable to add MessageId {0} to queuedCommandResults ConcurrentDictionary.", messageId));

View on GitHub (pinned to 16bc6e0711)

Solutions

  1. Guard every DevTools call with a liveness check: if (browser == null || browser.IsDisposed) return/skip before awaiting.
  2. Dispose of / stop issuing DevTools commands before disposing the ChromiumWebBrowser (cancel in-progress tasks or accept the exception).
  3. Do not cache a DevToolsClient beyond the lifetime of its owning browser; obtain a fresh client via browser.GetDevToolsClient() after recreating a browser.
  4. Catch ObjectDisposedException specifically in shutdown paths and treat it as a normal exit, not an error.

Example fix

// before
var result = await browser.GetDevToolsClient().Network.EnableAsync(); // throws if browser disposed mid-call

// after
if (browser == null || browser.IsDisposed) return;
var client = browser.GetDevToolsClient();
try
{
    await client.Network.EnableAsync();
}
catch (ObjectDisposedException) { /* shutting down, ignore */ }
Defensive patterns

Strategy: validation

Validate before calling

// Validate browser liveness before issuing DevTools commands.
if (browser == null || browser.IsDisposed) return;
var client = browser.GetDevToolsClient();
await client.Network.EnableAsync();

Type guard

public static bool IsDevToolsUsable(IBrowser browser) => browser != null && !browser.IsDisposed;

Try / catch

try { await client.Page.ReloadAsync(); }
catch (ObjectDisposedException) { /* browser torn down - expected during shutdown */ }

Prevention

When it happens

Trigger: Awaiting ExecuteDevToolsMethodAsync (or any generated DevTools domain method) after calling ChromiumWebBrowser.Dispose()/Close(); awaiting a DevTools call in a window-closing/cleanup handler; keeping a long-lived reference to a DevToolsClient and reusing it after the browser was recreated or navigated to a new popup that replaced the host.

Common situations: Race between an async DevTools command and the browser being torn down on application shutdown; calling DevTools methods from a finally block during disposal; holding the DevToolsClient in a static/singleton that outlives the browser instance.

Related errors


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