{"record":{"id":"6cf8d1b4b74d87a2","repo":"cefsharp/CefSharp","slug":"unable-to-invoke-executedevtoolsmethod-on-cef-ui-t","errorCode":null,"errorMessage":"Unable to invoke ExecuteDevToolsMethod on CEF UI Thread.","messagePattern":"Unable to invoke ExecuteDevToolsMethod on CEF UI Thread\\.","errorType":"exception","errorClass":"DevToolsClientException","httpStatus":null,"severity":"error","filePath":"CefSharp.Core/DevTools/DevToolsClient.cs","lineNumber":175,"sourceCode":"            }\n\n            //Currently on CEF UI Thread we can directly execute\n            if (CefThread.CurrentlyOnUiThread)\n            {\n                ExecuteDevToolsMethod(browserHost, messageId, method, parameters, methodResultContext);\n            }\n            //ExecuteDevToolsMethod can only be called on the CEF UI Thread\n            else if (CefThread.CanExecuteOnUiThread)\n            {\n                CefThread.ExecuteOnUiThread(() =>\n                {\n                    ExecuteDevToolsMethod(browserHost, messageId, method, parameters, methodResultContext);\n                });\n            }\n            else\n            {\n                queuedCommandResults.TryRemove(messageId, out methodResultContext);\n                throw new DevToolsClientException(\"Unable to invoke ExecuteDevToolsMethod on CEF UI Thread.\");\n            }\n\n            return taskCompletionSource.Task;\n        }\n\n        private void ExecuteDevToolsMethod(IBrowserHost browserHost, int messageId, string method, IDictionary<string, object> parameters, DevToolsMethodResponseContext methodResultContext)\n        {\n            try\n            {\n                var returnedMessageId = browserHost.ExecuteDevToolsMethod(messageId, method, parameters);\n                if (returnedMessageId == 0)\n                {\n                    throw new DevToolsClientException(string.Format(\"Failed to execute dev tools method {0}.\", method));\n                }\n                else if (returnedMessageId != messageId)\n                {\n                    //For some reason our message Id's don't match\n                    throw new DevToolsClientException(string.Format(\"Generated MessageId {0} doesn't match returned Message Id {1}\", returnedMessageId, messageId));","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/cefsharp/CefSharp/blob/16bc6e0711a4945be17e8bc4bc7ccf9469f3fdec/CefSharp.Core/DevTools/DevToolsClient.cs#L157-L193","documentation":"Thrown by ExecuteDevToolsMethodAsync when the call is not already on the CEF UI Thread and CefThread.CanExecuteOnUiThread is false. CanExecuteOnUiThread is only true while CEF is initialized and its UI thread message loop is running. Outside that window (before Cef.Initialize, after Cef.Shutdown, or during shutdown) there is no valid thread to dispatch the native call to, so CefSharp aborts cleanly.","triggerScenarios":"Issuing a DevTools command before Cef.Initialize has completed (e.g. in a static constructor or very early startup); issuing one after Cef.Shutdown has started; calling from a background thread during application exit; calling from a finalizer/destructor that runs after shutdown.","commonSituations":"Fire-and-forget DevTools calls queued during shutdown that execute after the message loop stops; unit tests that construct a DevToolsClient without fully initializing CEF; background service code that outlives the browser session.","solutions":["Ensure all DevTools calls happen strictly between Cef.Initialize completion and Cef.Shutdown - gate calls on a boolean flag you set/clear around Initialize/Shutdown.","Cancel outstanding async DevTools work (CancellationToken) before calling Cef.Shutdown so no in-flight call lands after the loop stops.","Move early-startup DevTools usage into a Cef.IsInitialized callback / the browser's IsBrowserInitializedChanged event rather than inline at startup.","Wrap shutdown-path calls in try/catch for DevToolsClientException and ignore them as expected."],"exampleFix":"// before - fires during/after shutdown\nawait client.Network.DisableAsync(); // may run after Cef.Shutdown begins\n\n// after - gate on liveness flag\nprivate static volatile bool _cefAlive;\n// set _cefAlive = true after Cef.Initialize; false before Cef.Shutdown\nif (!_cefAlive) return;\ntry { await client.Network.DisableAsync(); }\ncatch (DevToolsClientException) { /* shutdown race, ignore */ }","handlingStrategy":"validation","validationCode":"// Gate DevTools calls on a flag you control around Cef lifecycle.\nprivate static volatile bool _cefAlive;\n// set true after Cef.Initialize completes; false before Cef.Shutdown\nif (!_cefAlive) return;\nawait client.Network.DisableAsync();","typeGuard":"public static bool CanCallDevToolsNow() => _cefAlive && CefThread.CanExecuteOnUiThread;","tryCatchPattern":"try { await client.Network.DisableAsync(); }\ncatch (DevToolsClientException ex) when (ex.Message.Contains(\"CEF UI Thread\"))\n{ /* shutdown race - ignore */ }","preventionTips":["Issue DevTools commands only between Cef.Initialize completion and Cef.Shutdown","Cancel in-flight DevTools tasks before calling Cef.Shutdown","Never call DevTools from finalizers or post-shutdown background tasks"],"tags":["csharp","cefsharp","devtools","threading","ui-thread","lifecycle"],"backgroundTag":null,"analyzedSha":"16bc6e0711a4945be17e8bc4bc7ccf9469f3fdec","analyzedAt":"2026-08-13T19:57:05.828Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}