Stop a render error from blanking the whole app - #56
Open
Carlsaurus wants to merge 1 commit into
Open
Conversation
The frontend had NO error boundary anywhere -- grep for ErrorBoundary / componentDidCatch / getDerivedStateFromError returned nothing. In React that means any exception thrown during render unmounts the ENTIRE tree, so every render bug presents identically: a white page, no message, no stack, no way to report what happened. That is how "press Optimize on the flight page and it goes blank" arrived with nothing to act on. Adds components/ErrorBoundary.tsx and wraps each of the nine tab panels in one. The tab buttons live in <header>, above the panels, so a crashing tab now shows a copyable error with its component stack and a Try again button while the tab bar stays alive and every other tab keeps working. Verified end to end, not just by inspection: injected a throw at the top of FlightSimulation, reloaded, and confirmed the boundary rendered "Flight Simulation hit an error" with the stack while the rest of the app -- header, all nine tabs, the other panels -- stayed mounted and usable. Throw reverted. Note this does not by itself remove the underlying throw on the flight optimize path. I could not reproduce that one: the handler is correctly guarded (checks result.error, checks result.data, wrapped in try/catch -- though try/catch does not cover render), and every field the flight UI renders is a REQUIRED float or List[float] in the backend models, with all Optional sub-objects already guarded (results?.truncation?., results.propellant &&, and the !results?.trajectory early return). With the boundary in place the next occurrence prints the real error instead of a blank page, which is what makes it fixable. The Try again button is declared VIEW_ONLY in the checkout gating audit: it clears local error state and touches no design state. Frontend gating audit 4 passed; npm run build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
The frontend has no error boundary anywhere:
In React that means any exception thrown during render unmounts the entire tree. Every render bug then looks identical — a white page, no message, no stack, nothing to report. That's how "press Optimize on the flight page and it goes blank" reached us with nothing actionable.
The fix
Adds
components/ErrorBoundary.tsxand wraps each of the nine tab panels. The tab buttons live in<header>, above the panels, so a crashing tab now shows a copyable error with its component stack and a Try again button — while the tab bar stays alive and every other tab keeps working.Verified end to end
Not just by inspection. I injected a throw at the top of
FlightSimulation, reloaded, and confirmed the boundary rendered "Flight Simulation hit an error" with the stack, while the header, all nine tabs, and every other panel stayed mounted and usable. Then reverted the throw and confirmed a clean load.What this does not do
It does not by itself remove the underlying throw on the flight-optimize path — I could not reproduce that one. The handler is correctly guarded (checks
result.error, checksresult.data, wrapped in try/catch — though try/catch does not cover render), and every field the flight UI renders is a requiredfloatorList[float]in the backend models, with allOptionalsub-objects already guarded (results?.truncation?.,results.propellant &&, and the!results?.trajectoryearly return).With the boundary in place, the next occurrence prints the real error instead of a blank page — which is what makes it fixable.
Notes
The Try again button is declared
VIEW_ONLYin the checkout gating audit: it clears local error state and touches no design state.Frontend gating audit 4 passed;
npm run buildclean.🤖 Generated with Claude Code