From ea52381199d5e6468c70701febe79326349ceae6 Mon Sep 17 00:00:00 2001 From: Jack Levy Date: Sun, 1 Mar 2026 12:14:37 -0500 Subject: [PATCH] fix(notifications): replace em dash in ntfy Title header (ASCII-only), improve error surfacing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HTTP headers are ASCII-only; the em dash in "PocketVeto — Test Notification" caused a UnicodeEncodeError on every test attempt. Replaced with colon. Frontend catch blocks now extract the real server error detail from the axios response body instead of showing a generic fallback message. Authored-By: Jack Levy --- backend/app/api/notifications.py | 2 +- frontend/app/notifications/page.tsx | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/backend/app/api/notifications.py b/backend/app/api/notifications.py index 8c026c1..c53beea 100644 --- a/backend/app/api/notifications.py +++ b/backend/app/api/notifications.py @@ -116,7 +116,7 @@ async def test_ntfy( return NotificationTestResult(status="error", detail="Topic URL is required") headers: dict[str, str] = { - "Title": "PocketVeto — Test Notification", + "Title": "PocketVeto: Test Notification", "Priority": "default", "Tags": "white_check_mark", } diff --git a/frontend/app/notifications/page.tsx b/frontend/app/notifications/page.tsx index 95c6671..2c783b6 100644 --- a/frontend/app/notifications/page.tsx +++ b/frontend/app/notifications/page.tsx @@ -89,8 +89,11 @@ export default function NotificationsPage() { ntfy_password: authMethod === "basic" ? password : "", }); setNtfyTestResult(result); - } catch { - setNtfyTestResult({ status: "error", detail: "Request failed — check your topic URL" }); + } catch (e: unknown) { + const detail = + (e as { response?: { data?: { detail?: string } } })?.response?.data?.detail + ?? (e instanceof Error ? e.message : "Request failed"); + setNtfyTestResult({ status: "error", detail }); } finally { setNtfyTesting(false); } @@ -102,8 +105,11 @@ export default function NotificationsPage() { try { const result = await notificationsAPI.testRss(); setRssTestResult(result); - } catch { - setRssTestResult({ status: "error", detail: "Feed check failed" }); + } catch (e: unknown) { + const detail = + (e as { response?: { data?: { detail?: string } } })?.response?.data?.detail + ?? (e instanceof Error ? e.message : "Feed check failed"); + setRssTestResult({ status: "error", detail }); } finally { setRssTesting(false); }