From 47929c801fa62e60d566886c1b73bb44eb99ea7a Mon Sep 17 00:00:00 2001 From: Erhnysr Date: Sat, 25 Jul 2026 23:41:13 +0300 Subject: [PATCH] fix: surface API errors (rate limits, failures) in the app UIs The Terminal, Calendar, and Notes apps called /api/agent/generate and read `const { text } = await response.json()` without checking response.ok. On a non-OK response (e.g. the middleware's 429 rate limit, or a 500) `text` was undefined: Terminal/Calendar showed a generic message and Notes failed silently, so the rate limiter's "Please slow down" message never reached users. Check response.ok in all three, throw the server's message/error, and surface it: Terminal in its fallback line, Calendar in its error bubble, and Notes via a new inline error (previously it swallowed errors with no UI). --- components/apps/calendar.tsx | 12 +++++++++++- components/apps/notes.tsx | 23 +++++++++++++++++++++-- components/apps/terminal.tsx | 14 +++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/components/apps/calendar.tsx b/components/apps/calendar.tsx index 136b655..d5519b3 100644 --- a/components/apps/calendar.tsx +++ b/components/apps/calendar.tsx @@ -260,6 +260,13 @@ Keep each section brief (1-2 sentences max). Be helpful and conversational.`, }), }) + if (!response.ok) { + const errorBody = await response.json().catch(() => null) + throw new Error( + errorBody?.message || errorBody?.error || `Request failed (${response.status})`, + ) + } + const { text } = await response.json() setChatHistory((prev) => [...prev, { role: "assistant", content: text, isStructured: true }]) @@ -283,7 +290,10 @@ Keep each section brief (1-2 sentences max). Be helpful and conversational.`, ...prev, { role: "assistant", - content: "I encountered an error processing your request. Please try again.", + content: + error instanceof Error + ? error.message + : "I encountered an error processing your request. Please try again.", isStructured: false, }, ]) diff --git a/components/apps/notes.tsx b/components/apps/notes.tsx index e34f9e4..624f29b 100644 --- a/components/apps/notes.tsx +++ b/components/apps/notes.tsx @@ -59,6 +59,7 @@ export function Notes() { const [searchQuery, setSearchQuery] = useState("") const [isAnalyzing, setIsAnalyzing] = useState(false) const [analyzingNoteId, setAnalyzingNoteId] = useState(null) + const [aiError, setAiError] = useState(null) const currentNote = notes.find((n) => n.id === selectedNote) @@ -97,6 +98,7 @@ export function Notes() { setIsAnalyzing(true) setAnalyzingNoteId(noteId) + setAiError(null) setIsProcessing(true) setCurrentThinking(`Analyzing "${note.title}"...`) @@ -121,6 +123,13 @@ Respond with a JSON object (no markdown): }), }) + if (!response.ok) { + const errorBody = await response.json().catch(() => null) + throw new Error( + errorBody?.message || errorBody?.error || `Request failed (${response.status})`, + ) + } + const { text } = await response.json() // Parse the AI response @@ -148,8 +157,10 @@ Respond with a JSON object (no markdown): } catch { // Silently handle parse errors - AI response format may vary } - } catch { - // Silently handle categorization errors + } catch (error) { + setAiError( + error instanceof Error ? error.message : "Categorization failed. Please try again.", + ) } finally { setIsAnalyzing(false) setAnalyzingNoteId(null) @@ -357,6 +368,14 @@ Respond with a JSON object (no markdown): )} + {aiError && ( +
+

+ Categorization failed: {aiError} +

+
+ )} +