From dab7159cc59de1e8c77b5f92b58e86c1135f406a Mon Sep 17 00:00:00 2001 From: nessi Date: Tue, 17 Mar 2026 19:51:02 +0100 Subject: [PATCH] fix: improve error handling and display in desktop client enrollment flow Add formatInvokeError helper function to handle various error types from Tauri invoke calls with fallback messages. Update enroll_device to include response body in error message when enrollment fails with non-success status. Add windows_subsystem attribute to main.rs to suppress console window in release builds on Windows. --- desktop-client/src-tauri/src/lib.rs | 7 ++++++- desktop-client/src-tauri/src/main.rs | 2 ++ desktop-client/src/App.tsx | 16 ++++++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/desktop-client/src-tauri/src/lib.rs b/desktop-client/src-tauri/src/lib.rs index 5bdd16b..ddbf30c 100644 --- a/desktop-client/src-tauri/src/lib.rs +++ b/desktop-client/src-tauri/src/lib.rs @@ -153,7 +153,12 @@ async fn enroll_device( .map_err(|err| format!("Enrollment failed: {}", err))?; if !enroll_response.status().is_success() { - return Err(format!("Enrollment failed with status {}", enroll_response.status())); + let status = enroll_response.status(); + let body = enroll_response + .text() + .await + .unwrap_or_else(|_| "".into()); + return Err(format!("Enrollment failed with status {}: {}", status, body)); } let enroll = enroll_response diff --git a/desktop-client/src-tauri/src/main.rs b/desktop-client/src-tauri/src/main.rs index 46b6336..de7183b 100644 --- a/desktop-client/src-tauri/src/main.rs +++ b/desktop-client/src-tauri/src/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + fn main() { nexavpn_desktop::run(); } diff --git a/desktop-client/src/App.tsx b/desktop-client/src/App.tsx index 351dbaa..de93e8a 100644 --- a/desktop-client/src/App.tsx +++ b/desktop-client/src/App.tsx @@ -11,6 +11,18 @@ type EnrollmentState = { tunnelStrategy: string; }; +function formatInvokeError(err: unknown, fallback: string) { + if (typeof err === "string" && err.trim().length > 0) { + return err; + } + + if (err instanceof Error && err.message.trim().length > 0) { + return err.message; + } + + return fallback; +} + export function App() { const [serverUrl, setServerUrl] = useState("http://localhost"); const [username, setUsername] = useState(""); @@ -41,7 +53,7 @@ export function App() { }); setState(result); } catch (err) { - setError(err instanceof Error ? err.message : "Enrollment failed"); + setError(formatInvokeError(err, "Enrollment failed")); } finally { setLoading(false); } @@ -54,7 +66,7 @@ export function App() { setConnected((value) => !value); setError(null); } catch (err) { - setError(err instanceof Error ? err.message : "Tunnel action failed"); + setError(formatInvokeError(err, "Tunnel action failed")); } }