{"record":{"id":"14a925efe894231d","repo":"microsoft/aspire","slug":"browser-debug-connection-closed-by-the-remote-endpoint-with","errorCode":null,"errorMessage":"Browser debug connection closed by the remote endpoint with status '{closeStatus}' ({(int)closeStatus}): {result.CloseStatusDescription}","messagePattern":"Browser debug connection closed by the remote endpoint with status '(.+?)' \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Browsers/BrowserLogsCdpConnection.cs","lineNumber":465,"sourceCode":"    private readonly TimeSpan _closeTimeout = closeTimeout;\n    private readonly WebSocket _webSocket = webSocket;\n\n    public async Task SendAsync(ReadOnlyMemory<byte> frame, CancellationToken cancellationToken)\n    {\n        await _webSocket.SendAsync(frame, WebSocketMessageType.Text, endOfMessage: true, cancellationToken).ConfigureAwait(false);\n    }\n\n    public async Task<byte[]> ReceiveAsync(CancellationToken cancellationToken)\n    {\n        var buffer = new byte[16 * 1024];\n        using var messageBuffer = new MemoryStream();\n\n        while (true)\n        {\n            var result = await _webSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false);\n            if (result.MessageType == WebSocketMessageType.Close)\n            {\n                throw CreateUnexpectedConnectionClosureException(result);\n            }\n\n            // Large CDP events can span multiple websocket frames. Buffer until EndOfMessage so protocol parsing\n            // always sees one complete JSON message, matching the frames observed from a real browser.\n            messageBuffer.Write(buffer, 0, result.Count);\n            if (result.EndOfMessage)\n            {\n                return messageBuffer.ToArray();\n            }\n        }\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        try\n        {\n            if (_webSocket.State is WebSocketState.Open or WebSocketState.CloseReceived)\n            {","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Browsers/BrowserLogsCdpConnection.cs#L447-L483","documentation":"Thrown by BrowserLogsWebSocketCdpTransport.ReceiveAsync (BrowserLogsCdpConnection.cs:465) when the browser closes the CDP WebSocket instead of sending more messages. It is an InvalidOperationException raised because Aspire expects the browser debug connection to stay open for the lifetime of the tracked browser session, so a Close frame is unexpected and its status/description are surfaced as diagnostics for reconnect logic and resource logs.","triggerScenarios":"The remote browser sends a WebSocket Close frame during _webSocket.ReceiveAsync while the transport is reading CDP events — e.g. the browser process exits or is killed while logs are being streamed over the --remote-debugging-port WebSocket transport.","commonSituations":"The user closes the browser window; the browser crashes; the AppHost or OS kills the browser (timeout, shutdown); a proxy or firewall terminates the idle WebSocket; browser extensions force a restart of the browser process.","solutions":["Check the close status in the message: 1006/abnormal or empty description means the browser process died — inspect the browser's own logs/exit code first.","Ensure the browser is not closed manually while the AppHost is tracking it; keep the browser window open during the session.","Verify no proxy, VPN, or antivirus terminates idle WebSocket connections between the AppHost and the browser's debug port.","If the browser exits immediately, confirm the debug port is not already in use by another browser instance (another instance will exit with 'DevToolsActivePort file doesn't exist' style errors).","Dispose/recreate the BrowserLogsCdpConnection and relaunch the browser to re-establish the connection."],"exampleFix":"// before\nvar connection = new BrowserLogsCdpConnection(...);\nawait connection.StreamLogsForeverAsync(ct);\n\n// after\ntry\n{\n    await connection.StreamLogsForeverAsync(ct);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"closed by the remote endpoint\"))\n{\n    logger.LogWarning(ex, \"Browser CDP connection dropped; relaunching browser.\");\n    connection = await RelaunchBrowserAsync();\n}","handlingStrategy":"try-catch","validationCode":"// Before relying on a long-lived CDP session, confirm the browser process is alive:\nbool IsBrowserAlive(Process? browser) => browser is { HasExited: false };","typeGuard":"static bool IsUnexpectedClosure(InvalidOperationException ex) =>\n    ex.Message.StartsWith(\"Browser debug connection closed by the remote endpoint\", StringComparison.Ordinal);","tryCatchPattern":"try\n{\n    await transport.ReceiveAsync(ct);\n}\ncatch (InvalidOperationException ex) when (IsUnexpectedClosure(ex))\n{\n    logger.LogWarning(ex, \"CDP WebSocket closed by browser; scheduling relaunch.\");\n    await RelaunchBrowserAndReconnectAsync();\n}","preventionTips":["Do not close the browser window while the AppHost is tracking it.","Monitor the browser process exit before/at the same time as CDP errors to distinguish crash vs close.","Avoid proxies/VPNs that kill idle WebSockets between the AppHost and the debug port.","Ensure the debug port is exclusive to this browser instance."],"tags":["websocket","cdp","browser","connection-closed"],"backgroundTag":"connection-refused","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}