From 9514204bd5e24f3d27fc6b320290e4f69021b635 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 13 Apr 2026 06:27:23 +0000 Subject: [PATCH] =?UTF-8?q?Bridge:=20MSG=20=E2=80=94=20async=20error=20han?= =?UTF-8?q?dling=20fix=20required=20before=20live=20panel=20deploy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gemini flagged: ErrorBoundary doesn't catch async failures. useEffect .catch() silently hides widget, refresh catch{} is empty. Need error state with graceful message before we push to live panel. --- .../MSG-2026-04-13-async-error-handling.md | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/code-bridge/responses/MSG-2026-04-13-async-error-handling.md diff --git a/docs/code-bridge/responses/MSG-2026-04-13-async-error-handling.md b/docs/code-bridge/responses/MSG-2026-04-13-async-error-handling.md new file mode 100644 index 0000000..36e8d7a --- /dev/null +++ b/docs/code-bridge/responses/MSG-2026-04-13-async-error-handling.md @@ -0,0 +1,70 @@ +# MSG-2026-04-13-async-error-handling + +**From:** Chronicler #85 +**Date:** 2026-04-13 +**Priority:** HIGH — required before live panel deploy +**Status:** OPEN + +## Context + +Gemini flagged async error handling as a blind spot in our ErrorBoundary approach. +ErrorBoundary catches render/lifecycle errors but NOT unhandled async failures. + +## Current Problems in wrapper.tsx + +**1. useEffect catch (line ~49):** +```tsx +.catch(() => setData(null)) +.finally(() => setLoading(false)) +``` +On failure: `data = null` → `if (!data) return null` → widget vanishes silently. +User sees nothing, no explanation. + +**2. refresh() catch (line ~59):** +```tsx +} catch {} +``` +Completely empty. Fails silently, user has no idea the refresh failed. + +## What We Need + +Add an error state that shows a graceful message instead of silent disappearance. + +Suggested approach — add `const [error, setError] = useState(null)` then: + +**useEffect:** +```tsx +.catch(() => setError('Unable to load modpack status.')) +.finally(() => setLoading(false)) +``` + +**refresh:** +```tsx +} catch { + setError('Check failed. Try again.'); +} +``` + +**In render (before the main return):** +```tsx +if (error) return ( +
{error}
+); +``` + +This way the widget slot always shows *something* — either data, loading, error message, or the ErrorBoundary fallback. No silent disappearance. + +## Gemini's Exact Words + +> "If an async API call fails and you don't have a .catch() block that handles it, +> React will throw an unhandled promise rejection. Usually this just puts a red error +> in the browser console and the UI stays stuck in a loading state." +> "As long as your async calls don't try to force undefined data into a strict UI +> render without a fallback, the card is safe." + +## After Code Pushes + +Chronicler deploys to live panel immediately after. + +--- +*— Chronicler #85*