{"record":{"id":"928890e2cc157b1b","repo":"cefsharp/CefSharp","slug":"ibrowser","errorCode":null,"errorMessage":"IBrowser","messagePattern":"IBrowser","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"CefSharp.Core/DevTools/DevToolsClient.cs","lineNumber":138,"sourceCode":"            return ExecuteDevToolsMethodAsync<DevToolsMethodResponse>(method, parameters);\n        }\n\n        /// <summary>\n        /// Execute a method call over the DevTools protocol. This method can be called on any thread.\n        /// See the DevTools protocol documentation at https://chromedevtools.github.io/devtools-protocol/ for details\n        /// of supported methods and the expected <paramref name=\"parameters\"/> dictionary contents.\n        /// </summary>\n        /// <typeparam name=\"T\">The type into which the result will be deserialzed.</typeparam>\n        /// <param name=\"method\">is the method name</param>\n        /// <param name=\"parameters\">are the method parameters represented as a dictionary,\n        /// which may be empty.</param>\n        /// <returns>return a Task that can be awaited to obtain the method result</returns>\n        public Task<T> ExecuteDevToolsMethodAsync<T>(string method, IDictionary<string, object> parameters = null) where T : DevToolsDomainResponseBase\n        {\n            if (browser == null || browser.IsDisposed)\n            {\n                //TODO: Queue up commands where possible\n                throw new ObjectDisposedException(nameof(IBrowser));\n            }\n\n            var taskCompletionSource = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n            var methodResultContext = new DevToolsMethodResponseContext(\n                type: typeof(T),\n                setResult: o => taskCompletionSource.TrySetResult((T)o),\n                setException: taskCompletionSource.TrySetException,\n                syncContext: CaptureSyncContext ? SynchronizationContext.Current : SyncContext\n            );\n\n            var browserHost = browser.GetHost();\n\n            var messageId = browserHost.GetNextDevToolsMessageId();\n\n            if (!queuedCommandResults.TryAdd(messageId, methodResultContext))\n            {\n                throw new DevToolsClientException(string.Format(\"Unable to add MessageId {0} to queuedCommandResults ConcurrentDictionary.\", messageId));","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/cefsharp/CefSharp/blob/16bc6e0711a4945be17e8bc4bc7ccf9469f3fdec/CefSharp.Core/DevTools/DevToolsClient.cs#L120-L156","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvar result = await browser.GetDevToolsClient().Network.EnableAsync(); // throws if browser disposed mid-call\n\n// after\nif (browser == null || browser.IsDisposed) return;\nvar client = browser.GetDevToolsClient();\ntry\n{\n    await client.Network.EnableAsync();\n}\ncatch (ObjectDisposedException) { /* shutting down, ignore */ }","handlingStrategy":"validation","validationCode":"// Validate browser liveness before issuing DevTools commands.\nif (browser == null || browser.IsDisposed) return;\nvar client = browser.GetDevToolsClient();\nawait client.Network.EnableAsync();","typeGuard":"public static bool IsDevToolsUsable(IBrowser browser) => browser != null && !browser.IsDisposed;","tryCatchPattern":"try { await client.Page.ReloadAsync(); }\ncatch (ObjectDisposedException) { /* browser torn down - expected during shutdown */ }","preventionTips":["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"],"tags":["csharp","cefsharp","devtools","object-disposed","lifecycle","async"],"backgroundTag":null,"analyzedSha":"16bc6e0711a4945be17e8bc4bc7ccf9469f3fdec","analyzedAt":"2026-08-13T19:57:05.828Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}