From e51c53f247a4e687f0a4a6eaca37411454c218c3 Mon Sep 17 00:00:00 2001 From: Stefano Bertelli Date: Mon, 30 Mar 2026 22:51:22 -0500 Subject: [PATCH] fix: handle client disconnect during device creation Long-running async handlers (DB insert + WG events) can outlive the client connection. Guard all UI operations after async work with RuntimeError catches so disconnected clients don't crash. --- wiregui/pages/admin/devices.py | 19 ++++++++++++++----- wiregui/pages/devices.py | 18 +++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/wiregui/pages/admin/devices.py b/wiregui/pages/admin/devices.py index 0357906..3d595ed 100644 --- a/wiregui/pages/admin/devices.py +++ b/wiregui/pages/admin/devices.py @@ -129,13 +129,22 @@ async def admin_devices_page(): server_pubkey = await get_server_public_key() config_text = build_client_config(device, private_key, server_pubkey) - create_dialog.close() - _reset_create_form() - await refresh_table() - _show_config_dialog(device.name, config_text) + try: + create_dialog.close() + _reset_create_form() + await refresh_table() + _show_config_dialog(device.name, config_text) + except RuntimeError: + pass # Client navigated away during async work + + except RuntimeError: + pass # Client disconnected except Exception as e: logger.error("Failed to create device: {}", e) - ui.notify(f"Error: {e}", type="negative") + try: + ui.notify(f"Error: {e}", type="negative") + except RuntimeError: + pass def _reset_create_form(): create_name.value = "" diff --git a/wiregui/pages/devices.py b/wiregui/pages/devices.py index 326c55f..a26fd03 100644 --- a/wiregui/pages/devices.py +++ b/wiregui/pages/devices.py @@ -113,14 +113,22 @@ async def devices_page(): server_pubkey = await get_server_public_key() config_text = build_client_config(device, private_key, server_pubkey) - create_dialog.close() - _reset_create_form() - await refresh_table() - _show_config_dialog(device.name, config_text) + try: + create_dialog.close() + _reset_create_form() + await refresh_table() + _show_config_dialog(device.name, config_text) + except RuntimeError: + pass # Client navigated away during async work + except RuntimeError: + pass # Client disconnected except Exception as e: logger.error("Failed to create device: {}", e) - ui.notify(f"Error: {e}", type="negative") + try: + ui.notify(f"Error: {e}", type="negative") + except RuntimeError: + pass def _reset_create_form(): create_name.value = ""