An Error Boundary is a React component that catches JavaScript errors anywhere in the component tree, logs those errors, and displays a user-friendly fallback UI instead of crashing the entire app.
File: frontend/src/components/ErrorBoundary.jsx
A class component that implements React Error Boundary lifecycle methods:
getDerivedStateFromError(error) - Static Method
- Called during render phase when an error is caught
- Returns new state to trigger fallback UI render
- Runs before componentDidCatch
- Purpose: Update UI state to show error message
static getDerivedStateFromError(error) {
return {
hasError: true,
errorMessage: error?.message || 'An unexpected error occurred',
};
}componentDidCatch(error, errorInfo) - Instance Method
- Called during commit phase (after render fails)
- Receives error object and errorInfo with componentStack
- Can perform side effects (logging, error reporting)
- Purpose: Log errors and send to external services
componentDidCatch(error, errorInfo) {
console.error('Error caught by ErrorBoundary:', error);
console.error('Error Info:', errorInfo);
// Store error details for display
this.setState({
errorDetails: {
message: error?.message,
stack: error?.stack,
componentStack: errorInfo?.componentStack,
timestamp: new Date().toISOString(),
},
});
// Optionally log to backend
this.logErrorToBackend(error, errorInfo);
}{
hasError: false, // Whether an error has been caught
errorMessage: '', // User-friendly error message
errorDetails: null, // Full error stack and component info
}-
User-Friendly Fallback UI
- Shows error emoji icon (
⚠️ ) - Friendly title: "Oops! Something Went Wrong"
- Context-appropriate message
- Helpful instruction: "Try reloading the page"
- Prominent "Reload" button
- Shows error emoji icon (
-
Development Error Details
- In development mode: Shows expandable details with full error stack
- Includes component stack trace from React
- Includes timestamp and error message
- Only visible in
NODE_ENV === 'development'
-
Error Logging
- Console logging (always)
- Backend logging (POST to /api/errors)
- Includes user agent, URL, timestamp
- Non-blocking (wrapped in try-catch)
-
Reload Functionality
- Button triggers
window.location.reload() - Allows user to recover app state
- Simple and reliable recovery method
- Button triggers
File: frontend/src/App.jsx
ErrorBoundary wraps the entire app at the highest level:
export default function App() {
return (
<ErrorBoundary>
<AuthProvider>
<LoadingProvider>
<AppContent />
</LoadingProvider>
</AuthProvider>
</ErrorBoundary>
);
}Why at the top level?
- Catches errors in ALL child components
- Catches errors in providers (less common but possible)
- Prevents entire app from going blank
- Provides consistent error handling across app
The fallback UI includes:
- Centered container with gradient background
- White error box with shadow and rounded corners
- Responsive design with proper padding and max-width
- Visual hierarchy with icon, title, message
- Dev-friendly details section (hidden in production)
- Green action button matching app theme
- Component render errors
- Lifecycle method errors (except async ones)
- Constructor errors
- Errors in any child component
- Event handler errors (use try-catch in handlers)
- Async code errors (setTimeout, promises)
- Server-side rendering errors
- Errors in the boundary itself
Example - Event Handler (NOT caught):
// This error won't be caught by boundary
// Need try-catch inside handler
<button onClick={() => throw new Error('Test')}>Click</button>
// Correct approach:
<button onClick={() => {
try {
// risky operation
} catch (e) {
// handle error
}
}}>Click</button>✅ A component error shows a friendly message instead of a blank screen
- Error boundary catches component render errors
- Displays user-friendly fallback UI
- Shows "Oops! Something Went Wrong" message
- App remains interactive (not blank white screen)
✅ The fallback UI includes a Reload button that refreshes the page
- Button styled as primary action (green)
- Calls
window.location.reload()on click - Allows user to recover app without hard refresh
- Page reloads and app reinitializes
✅ Error details are logged to the browser console
componentDidCatchlogs to console- Includes error object with stack trace
- Includes errorInfo with component stack
- Always logged regardless of mode
✅ The error boundary does not catch errors in event handlers (expected behavior)
- Error boundaries only catch render errors
- Event handler errors require try-catch
- This is standard React behavior (not a limitation)
- Can be written in eventhandler code if needed
✅ The app recovers normally after reloading
- Page reload reinitializes all components
- Auth state rehydrated from localStorage if stored
- No permanent damage from error
- App returns to normal functioning state
The component attempts to log errors to /api/errors:
logErrorToBackend = (error, errorInfo) => {
try {
fetch('/api/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: error?.message || 'Unknown error',
stack: error?.stack,
componentStack: errorInfo?.componentStack,
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: new Date().toISOString(),
}),
}).catch(e => console.error('Failed to log error to backend:', e));
} catch (err) {
console.error('Error logging to backend:', err);
}
};Features:
- Non-blocking (doesn't affect user experience)
- Safe error handling (try-catch wrapped)
- Includes useful debugging info
- Backend can ignore if endpoint not implemented
- Can be implemented later without changing component
Example Backend Endpoint (future enhancement):
// POST /api/errors
// Could store errors in database for analysis
// Could send alerts to developers
// Could track error patternsOption 1: Add test error to a component:
function TestErrorComponent() {
if (true) throw new Error('Test error');
return <div>Content</div>;
}
// Then use: <TestErrorComponent /> somewhereOption 2: Use browser console:
// In DevTools console while app is running:
throw new Error('Manual test error');
// This will trigger the boundary!Expected Behavior:
- Component renders normally
- Error is thrown during render
- ErrorBoundary catches it
- Fallback UI appears with error message
- Console shows error logs
- User can click "Reload Page" button
- Page reloads, app recovers
When NODE_ENV === 'development':
- Error details section is visible
- Expandable
<details>element - Shows full error stack and component stack
- Helps with debugging
When NODE_ENV === 'production':
- Error details section is hidden
- Shows only user-friendly message
- Errors still logged to console
- Backend error logging still works
Requires:
- React 16.8+ (error boundaries added in 16.0)
- Modern browser (all modern browsers support)
No additional dependencies - uses standard React APIs
-
frontend/src/components/ErrorBoundary.jsx (NEW)
- 183 lines
- React class component
- Error boundary implementation
- Fallback UI and styling
-
frontend/src/App.jsx (MODIFIED)
- Added import:
import ErrorBoundary from './components/ErrorBoundary' - Wrapped return statement with
<ErrorBoundary>component - No changes to existing logic or providers
- Added import:
state = {
hasError: false, // Triggered by getDerivedStateFromError
errorMessage: '', // From error.message
errorDetails: null, // Set in componentDidCatch
}if (this.state.hasError) {
return <ErrorFallback UI />; // Show error screen
}
return this.props.children; // Normal renderThe errorInfo parameter includes:
componentStack: Call stack of components that threw- Trace of React component hierarchy
- Useful for debugging which component failed
Possible improvements without changing current implementation:
-
Backend Integration
- Create
/api/errorsendpoint - Store errors in database
- Create error dashboard
- Set up error notifications
- Create
-
Error Recovery Strategies
- Auto-reload after timeout
- Retry with exponential backoff
- Fallback to previous state
-
Error Tracking Service
- Integrate with Sentry or similar
- Track error patterns
- Alert on critical errors
-
User Communication
- Error code for support reference
- Support contact info in fallback UI
- Automatic error report generation
-
Development Tools
- Error overlay in dev
- Component error isolation
- Error history tracking
Cause: Error might be in event handler or async code Solution: Use try-catch in event handlers, wrap promises
Cause: Production build hides details
Solution: Check NODE_ENV or use development build
Cause: Unusual page setup or routing issues Solution: Check browser console for errors during reload
Cause: Error in ErrorBoundary itself or outer error Solution: Check console; boundary errors not caught by itself
✅ Error boundary catches component render errors
✅ Shows friendly fallback UI instead of blank screen
✅ Includes reload button for user recovery
✅ Logs errors to console for debugging
✅ Optional backend error logging
✅ Development-friendly with detailed error info
✅ Production-friendly with user-facing messages
✅ Zero breaking changes to existing code
✅ All acceptance criteria met