# 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*