Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions NetBird/Source/App/ViewModels/MainViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,14 @@ class ViewModel: ObservableObject {
self.logger.info("connect: Task started, calling networkExtensionAdapter.start()")
await self.networkExtensionAdapter.start()
self.logger.info("connect: networkExtensionAdapter.start() completed")
// If start() returned but VPN never launched (e.g. IPC failed to get login URL)
// and the browser login sheet is not showing, the tunnel won't start on its own.
// Reset the stuck "Connecting..." state so the user can try again.
// start() returns as soon as startVPNTunnel() is called — the tunnel process
// hasn't launched yet and extensionState is still .disconnected at this point.
// Wait long enough for the tunnel to start and for the polling cycle to pick up
// the new NEVPNStatus before deciding whether the launch genuinely failed.
try? await Task.sleep(nanoseconds: 8_000_000_000) // 8 seconds
// If after the wait the state is still disconnected and no browser login sheet
// is visible, the tunnel failed to start (e.g. IPC error). Reset the stuck
// "Connecting..." state so the user can try again.
if self.extensionState == .disconnected && !self.networkExtensionAdapter.showBrowser {
self.connectPressed = false
self.updateVPNDisplayState()
Expand Down
Loading