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
- Guard every DevTools call with a liveness check: if (browser == null || browser.IsDisposed) return/skip before awaiting.
- Dispose of / stop issuing DevTools commands before disposing the ChromiumWebBrowser (cancel in-progress tasks or accept the exception).
- Do not cache a DevToolsClient beyond the lifetime of its owning browser; obtain a fresh client via browser.GetDevToolsClient() after recreating a browser.
- 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
- Obtain the DevToolsClient fresh from the browser each session rather than caching it long-term
- Cancel outstanding DevTools tasks before disposing the browser
- Treat ObjectDisposedException in shutdown paths as normal, not as a bug
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
- Unable to invoke ExecuteDevToolsMethod on CEF UI Thread.
- Unable to add MessageId {0} to queuedCommandResults Concurre
- Failed to execute dev tools method {0}.
- Generated MessageId {0} doesn't match returned Message Id {1
- Not currently supported.
AI-assisted analysis of cefsharp/CefSharp@16bc6e0711 (2026-08-13).
Data as JSON: /api/errors/928890e2cc157b1b.
Report an issue: GitHub.