microsoft/aspire · error · InvalidOperationException

Tracked browser protocol frame was malformed.

Error message

Tracked browser protocol frame was malformed.

What it means

This library tracks browser (Chrome DevTools Protocol) traffic and parses each CDP frame's header with a Utf8JsonReader. After parsing an opening '{', it expects an object property name; anything else (a bare value, array, invalid structure) means the frame is not a valid CDP message object, so this InvalidOperationException is thrown. It signals the tracked browser sent a frame the parser cannot interpret.

Solutions

  1. Log the raw frame with DescribeFrame to inspect what was actually received
  2. Verify the browser binary/version is a standard Chromium build supporting CDP over the expected transport
  3. Check for proxies or wrappers intercepting the browser DevTools websocket/stream
  4. Ensure frame boundaries are read correctly before calling ParseMessageHeader (no partial frames)
  5. Catch InvalidOperationException around frame parsing and skip/reconnect to the browser

Example fix

// before
var header = BrowserLogsCdpProtocol.ParseMessageHeader(frame);
// after
BrowserLogsCdpMessageHeader? header;
try
{
    header = BrowserLogsCdpProtocol.ParseMessageHeader(frame);
}
catch (InvalidOperationException ex)
{
    logger.LogWarning(ex, "Skipping malformed browser protocol frame");
    return;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (framePayload.IsEmpty || framePayload[0] != (byte)'{')
{
    logger.LogWarning("Skipping non-object browser frame: {Frame}", BrowserLogsCdpProtocol.DescribeFrame(framePayload));
    return;
}

Try / catch

try
{
    var header = BrowserLogsCdpProtocol.ParseMessageHeader(frame);
}
catch (InvalidOperationException ex)
{
    logger.LogWarning(ex, "Malformed CDP frame skipped");
}

Prevention

When it happens

Trigger: ParseMessageHeader receives a frame payload whose JSON is not an object with property names at the expected position - e.g. a JSON array, a bare scalar like "hello" or 42, or a malformed/desynchronized stream where the reader lands on a non-PropertyName token.

Common situations: The browser or proxy sends a non-CDP message over the socket (e.g. an HTML error page, a plain text keepalive), a custom Chrome/Edge channel or headless shell emits an unexpected framing, or the frame framing layer mis-splits boundaries so partial/garbled JSON reaches the parser.

Understand the failure class

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/0aaccb02f535b2ec. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Browsers/BrowserLogsCdpProtocol.cs:83

        if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject)
        {
            throw new InvalidOperationException("Tracked browser protocol frame was not a JSON object.");
        }

        long? id = null;
        string? method = null;
        string? sessionId = null;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
            {
                break;
            }

            if (reader.TokenType != JsonTokenType.PropertyName)
            {
                throw new InvalidOperationException("Tracked browser protocol frame was malformed.");
            }

            var propertyName = reader.GetString();
            if (!reader.Read())
            {
                throw new InvalidOperationException("Tracked browser protocol frame ended unexpectedly.");
            }

            switch (propertyName)
            {
                case "id":
                    if (!reader.TryGetInt64(out var parsedId))
                    {
                        throw new InvalidOperationException("Tracked browser protocol response id was not an integer.");
                    }

                    id = parsedId;
                    break;

View on GitHub (pinned to 25830f84bd)