cefsharp/CefSharp · error · DevToolsClientException
Failed to execute dev tools method
Error message
Failed to execute dev tools method {0}. What it means
Thrown by the private ExecuteDevToolsMethod helper when IBrowserHost.ExecuteDevToolsMethod returns 0. A zero return means the native CEF call did not dispatch the DevTools protocol message - typically because the browser/host is not ready (no underlying WebContents), the method name is unknown, or the host is shutting down. The exception text formats in the method name that failed.
Solutions
- Wait for the browser's IsBrowserInitializedChanged event (IsBrowserInitialized == true) before issuing DevTools commands.
- Prefer the generated strongly-typed DevTools domain client (e.g. client.Network.EnableAsync()) over raw method strings - it uses names valid for the bundled CEF.
- Verify the method name is supported by the Chromium version embedded in your CefSharp package (check the DevTools protocol schema for that CEF major version).
- Await the Task and handle DevToolsClientException with a retry/recovery policy for transient 'not yet ready' states.
Example fix
// before - host not ready
await browser.GetDevToolsClient().ExecuteDevToolsMethodAsync<object>("Page.reload", null); // returns 0
// after - wait for init, use typed client
await ((Task)browser.SynchronizationContextAsync()); // ensure initialized
if (!browser.IsBrowserInitialized) await WaitForInit(browser);
await client.Page.ReloadAsync(); Defensive patterns
Strategy: validation
Validate before calling
// Wait for browser init before sending DevTools commands.
if (!browser.IsBrowserInitialized)
await Task.Run(() => { while (!browser.IsBrowserInitialized) Thread.Sleep(20); });
await client.Page.ReloadAsync(); Type guard
public static bool BrowserReadyForDevTools(IBrowser b) => b != null && !b.IsDisposed && b.IsBrowserInitialized;
Try / catch
try { await client.Page.ReloadAsync(); }
catch (DevToolsClientException ex) when (ex.Message.StartsWith("Failed to execute dev tools method"))
{ /* host not ready / unknown method - retry or fall back */ } Prevention
- Use generated typed domain clients (client.Page.*, client.Network.*) rather than raw method strings
- Wait for IsBrowserInitialized before any DevTools call
- Confirm method names exist in the Chromium version bundled with your CefSharp package
When it happens
Trigger: Calling a DevTools method before the browser's underlying host/WebView is initialized; passing an empty or unrecognised method string; calling after the host is being torn down. The thrown exception is captured and routed to the awaiting Task via methodResultContext.SetException, so the caller observes it as a faulted Task rather than a synchronous throw.
Common situations: Sending DevTools commands in OnFrameLoadStart before IsBrowserInitialized; typos in raw method names when using the untyped ExecuteDevToolsMethodAsync(string, dict) overload; version skew where a method exists in newer Chromium but not the CEF build shipped with the CefSharp version in use.
Related errors
- Generated MessageId doesn't match returned Message Id
- IBrowser
- Not currently supported.
- is required
- Unable to add MessageId
AI-assisted analysis of cefsharp/CefSharp@16bc6e0711 (2026-08-13).
Data as JSON: /api/errors/80f0b2e6cf7e951b.
Report an issue: GitHub.
Appendix: source
Thrown at CefSharp.Core/DevTools/DevToolsClient.cs:188
});
}
else
{
queuedCommandResults.TryRemove(messageId, out methodResultContext);
throw new DevToolsClientException("Unable to invoke ExecuteDevToolsMethod on CEF UI Thread.");
}
return taskCompletionSource.Task;
}
private void ExecuteDevToolsMethod(IBrowserHost browserHost, int messageId, string method, IDictionary<string, object> parameters, DevToolsMethodResponseContext methodResultContext)
{
try
{
var returnedMessageId = browserHost.ExecuteDevToolsMethod(messageId, method, parameters);
if (returnedMessageId == 0)
{
throw new DevToolsClientException(string.Format("Failed to execute dev tools method {0}.", method));
}
else if (returnedMessageId != messageId)
{
//For some reason our message Id's don't match
throw new DevToolsClientException(string.Format("Generated MessageId {0} doesn't match returned Message Id {1}", returnedMessageId, messageId));
}
}
catch (Exception ex)
{
queuedCommandResults.TryRemove(messageId, out _);
methodResultContext.SetException(ex);
}
}
/// <inheritdoc/>
public void Dispose()
{
//Dispose can be called from different ThreadsView on GitHub (pinned to 16bc6e0711)