@@ -287,23 +287,26 @@ final class AppState {
287287 // If the active connection was edited, its URL or credentials may now point
288288 // at a different server, so swapping the client alone isn't enough — the
289289 // displayed streams/selection/server-info would be stale and queries would
290− // 404. Reconnect end to end (re-validate health, reload streams/filters/
291− // about). Clear the stream selection first so a now-missing stream doesn't
292− // keep driving detail-tab requests during the reconnect.
290+ // 404. The caller is responsible for the actual reconnect (re-validate
291+ // health, reload streams/filters/about); we only clear the now-possibly-
292+ // stale UI state here, since `performConnect` skips its own cleanup when the
293+ // connection id is unchanged. We must NOT also spawn a connect here: the
294+ // sole caller (ConnectionSheet.saveAndConnect) already connects right after,
295+ // and a second connect would run two full reconnects and flash the UI twice.
293296 if activeConnection?.id == connection.id {
294− // `performConnect` skips its stale-state cleanup because the id is
295− // unchanged, but the edited URL/credentials may point at a different
296− // server. Clear the stream-specific UI state here so a leftover sidebar
297− // search filter doesn't hide the new server's streams and a
298− // stream-specific tab doesn't linger with no valid selection.
297+ // Clear the stream-specific UI state so a leftover sidebar search filter
298+ // doesn't hide the new server's streams and a stream-specific tab
299+ // doesn't linger with no valid selection.
299300 selectedStream = nil
300301 streamSearchText = ""
301302 currentTab = .query
302− // Drop the previous server's cached `about` too — performConnect skips
303− // its own clear (id unchanged), so without this ServerInfoView keeps
304− // painting the old server's version/storage until the new /about lands.
303+ // Drop the previous server's cached `about`, stream list, and filters —
304+ // performConnect skips its own clear (id unchanged), so without this the
305+ // sidebar keeps rendering server A's streams/filters and ServerInfoView
306+ // paints the old version/storage until the new server's responses land.
305307 serverAbout = nil
306− Task { await connect(to: connection) }
308+ streams = []
309+ filters = []
307310 }
308311 }
309312