From 9a2c9b33941d8e6cfac596a6c8d7fda409c34735 Mon Sep 17 00:00:00 2001 From: Alistair Smith Date: Tue, 17 Feb 2026 11:48:31 -0800 Subject: [PATCH] fix: drain CDP messages after doConnect to prevent message loss on reconnect receiveMessagesOnInspectorThread was draining messages from the queue before checking if the connection needed doConnect. If the connection was Pending, it called doConnect and returned early, dropping the already-drained messages on the floor. Move the doConnect check before the message drain so messages that arrive during reconnection are not lost. --- src/bun.js/bindings/BunDebugger.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/bun.js/bindings/BunDebugger.cpp b/src/bun.js/bindings/BunDebugger.cpp index 15d886d376..baaebed77b 100644 --- a/src/bun.js/bindings/BunDebugger.cpp +++ b/src/bun.js/bindings/BunDebugger.cpp @@ -346,6 +346,21 @@ public: // tasks pile up for after the loop exits). if (!(this->pauseFlags.load() & kInPauseLoop)) this->jsThreadMessageScheduled.store(false); + + // Connect pending connections BEFORE draining messages. + // If we drain first and then doConnect returns early, the drained + // messages would be lost (dropped on stack unwind). + auto& dispatcher = globalObject->inspectorDebuggable(); + Inspector::JSGlobalObjectDebugger* debugger = reinterpret_cast(globalObject->debugger()); + + if (!debugger && connectIfNeeded && this->status == ConnectionStatus::Pending) { + this->doConnect(context); + // doConnect calls receiveMessagesOnInspectorThread recursively, + // but jsThreadMessages may have been empty at that point. + // Fall through to drain any messages that arrived during doConnect. + debugger = reinterpret_cast(globalObject->debugger()); + } + WTF::Vector messages; { @@ -353,15 +368,7 @@ public: this->jsThreadMessages.swap(messages); } - auto& dispatcher = globalObject->inspectorDebuggable(); - Inspector::JSGlobalObjectDebugger* debugger = reinterpret_cast(globalObject->debugger()); - if (!debugger) { - if (connectIfNeeded && this->status == ConnectionStatus::Pending) { - this->doConnect(context); - return; - } - for (auto message : messages) { dispatcher.dispatchMessageFromRemote(WTF::move(message));