cefsharp/CefSharp · error · DevToolsClientException

Generated MessageId {0} doesn't match returned Message Id {1

Error message

Generated MessageId {0} doesn't match returned Message Id {1}

What it means

Defensive check inside ExecuteDevToolsMethod: after calling IBrowserHost.ExecuteDevToolsMethod(messageId, ...) the returned id must equal the messageId passed in. A mismatch would mean CEF allocated or returned a different correlation id than requested, which would break the async result routing in queuedCommandResults. In correct builds this never happens; like the TryAdd guard it flags a native contract violation.

Source

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

                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 Threads
            //CEF maintains a reference and the user
            //maintains a reference, we in a rare case
            //we end up disposing of #3725 twice from different
            //threads. This will ensure our dispose only runs once.
            if (Interlocked.Increment(ref disposeCount) == 1)

View on GitHub (pinned to 16bc6e0711)

Solutions

  1. Ensure all CefSharp packages (CefSharp.Common, CefSharp.Core, CefSharp.Wpf/WinForms/OffScreen, CefSharp.Core.Runtime) are pinned to the exact same version - clear bin/obj and restore.
  2. Update to the latest patch release of your CefSharp line in case the id-handling bug was fixed.
  3. If reproducible after version alignment, capture the CEF version (Cef.CefVersion) and file a CefSharp issue with a minimal repro.
  4. Treat the faulted Task defensively in the caller (log + retry/fallback) while the underlying issue is investigated.

Example fix

// No caller-side data fix - it is an internal contract check. Caller can only react:
try
{
    await client.Page.NavigateAsync(url);
}
catch (DevToolsClientException ex) when (ex.Message.Contains("doesn't match returned Message Id"))
{
    logger.Error(ex, "CefSharp native/managed version mismatch detected - re-pin package versions.");
    throw;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No caller precondition; verify package version alignment as the preventive check.
System.Diagnostics.Debug.Assert(typeof(CefSharp.Cef).Assembly.GetName().Version == typeof(CefSharp.Core.RequestContext).Assembly.GetName().Version, "CefSharp version mismatch");

Try / catch

try { await client.Page.NavigateAsync(url); }
catch (DevToolsClientException ex) when (ex.Message.Contains("doesn't match returned Message Id"))
{ logger.Fatal(ex, "CefSharp native/managed version mismatch - re-pin packages."); throw; }

Prevention

When it happens

Trigger: A CEF/Chromium build that does not echo the caller-supplied message id; a bug in the CefSharp native interop layer; using a mismatched CefSharp.Core.Runtime (native) binary against a managed assembly of a different version. The exception is delivered asynchronously to the awaiter via SetException.

Common situations: Mixing CefSharp NuGet package versions across a solution (e.g. CefSharp.Common at one version but a stale CefSharp.Core.Runtime.dll in the output); building native bits from a different CEF branch than the managed wrapper; a genuine native regression in a specific CEF release.

Related errors


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