Environment
- App: proton-vpn-gtk-app 4.16.4
- Package: python-proton-vpn-network-manager (latest Arch/AUR)
- Python: 3.14.5
- NetworkManager: 1.56.1
- OS: Arch Linux (CachyOS)
Bug Description
On startup, protonvpn-app crashes with asyncio.exceptions.TimeoutError before the window appears.
Root cause is in killswitch/wireguard/nmclient.py — the _on_connection_removed callback calls connection.delete_finish(result) on success but never calls future_interface_removed.set_result(None). The future can only be resolved via the device-removed GLib signal. When no WireGuard kill switch interface is active (e.g. after reboot, or after manually deleting stale pvpn-killswitch-perm NM connections), that signal never fires and the 10-second asyncio timeout in _wrap_future triggers.
This affects both killswitch=2 (permanent, tries to enable) and killswitch=0 (disabled, tries to remove) on startup.
Traceback
File "/usr/bin/protonvpn-app", line 8, in <module>
sys.exit(main())
File ".../proton/vpn/app/gtk/__main__.py", line 35, in main
controller = Controller.get(executor, exception_handler)
File ".../proton/vpn/app/gtk/controller.py", line 74, in get
executor.submit(controller.initialize_vpn_connector).result()
File ".../proton/vpn/core/vpnconnector.py", line 288, in initialize_state
await self._update_state(state)
File ".../proton/vpn/connection/states.py", line 196, in run_tasks
await self.context.kill_switch.disable()
File ".../killswitch/wireguard/wgkillswitch.py", line 76, in disable
await self._ks_handler.remove_killswitch_connection()
File ".../killswitch/wireguard/killswitch_connection_handler.py", line 291, in _remove_connection
await _wrap_future(self.nm_client.remove_connection_async(connection))
File ".../killswitch/wireguard/killswitch_connection_handler.py", line 56, in _wrap_future
return await asyncio.wait_for(...)
asyncio.exceptions.TimeoutError
Affected Code
killswitch/wireguard/nmclient.py, remove_connection_async method:
def _on_connection_removed(connection, result, _user_data):
try:
connection.delete_finish(result)
# BUG: future_interface_removed.set_result(None) is never called on success.
# Future only resolves via device-removed signal, which never fires
# if no WireGuard interface is currently active.
except Exception as exc:
future_interface_removed.set_exception(...)
Proposed Fix
def _on_connection_removed(connection, result, _user_data):
try:
connection.delete_finish(result)
if not future_interface_removed.done():
future_interface_removed.set_result(None) # resolve on success
except Exception as exc:
future_interface_removed.set_exception(...)
Steps to Reproduce
- Have
killswitch set to 0 or 2 in ~/.config/Proton/VPN/settings.json
- Ensure no active
pvpnksintrf1 WireGuard interface exists (fresh boot or after removing stale NM connections)
- Launch
protonvpn-app — crashes immediately with TimeoutError
Workaround
None currently available without patching the source or downgrading Python.
Bug reported via automated analysis using Claude Code
Environment
Bug Description
On startup,
protonvpn-appcrashes withasyncio.exceptions.TimeoutErrorbefore the window appears.Root cause is in
killswitch/wireguard/nmclient.py— the_on_connection_removedcallback callsconnection.delete_finish(result)on success but never callsfuture_interface_removed.set_result(None). The future can only be resolved via thedevice-removedGLib signal. When no WireGuard kill switch interface is active (e.g. after reboot, or after manually deleting stalepvpn-killswitch-permNM connections), that signal never fires and the 10-second asyncio timeout in_wrap_futuretriggers.This affects both
killswitch=2(permanent, tries to enable) andkillswitch=0(disabled, tries to remove) on startup.Traceback
Affected Code
killswitch/wireguard/nmclient.py,remove_connection_asyncmethod:Proposed Fix
Steps to Reproduce
killswitchset to0or2in~/.config/Proton/VPN/settings.jsonpvpnksintrf1WireGuard interface exists (fresh boot or after removing stale NM connections)protonvpn-app— crashes immediately withTimeoutErrorWorkaround
None currently available without patching the source or downgrading Python.
Bug reported via automated analysis using Claude Code