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*