Files
firefrost-services/docs/code-bridge/archive/MSG-2026-04-13-async-error-handling.md
Claude (Chronicler #83 - The Compiler) 0caddef86d Fix async error handling + build.sh copy/inject separation
wrapper.tsx:
- Added error state — shows graceful message instead of silent vanish
- useEffect catch sets error string, not null data
- refresh() catch sets error string, not empty catch
- Error UI shows gray card with message in widget slot

build.sh:
- ALWAYS copies TSX files (even on reinstall — fixes stale component bug)
- Separated copy step from injection step
- ErrorBoundary upgrade path: removes bare <ModpackVersionCard />,
  replaces with wrapped version
- Imports added independently (not as one sed block)
- Renumbered sections for clarity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 01:31:44 -05:00

1.9 KiB

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):

.catch(() => setData(null))
.finally(() => setLoading(false))

On failure: data = nullif (!data) return null → widget vanishes silently. User sees nothing, no explanation.

2. refresh() catch (line ~59):

} 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<string | null>(null) then:

useEffect:

.catch(() => setError('Unable to load modpack status.'))
.finally(() => setLoading(false))

refresh:

} catch {
    setError('Check failed. Try again.');
}

In render (before the main return):

if (error) return (
    <div className="text-gray-400 text-xs px-2 py-1">{error}</div>
);

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