--- id: wiki-2026-0508-error-handling-and-stability title: Error Handling and Stability category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Frontend Error Boundaries, Error Recovery] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [errors, stability, observability, sentry] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: TypeScript framework: React/Vue --- # Error Handling and Stability ## 매 한 줄 > **"매 frontend stability = error 의 isolation + telemetry + graceful degradation."**. 매 single uncaught error가 매 SPA 의 전체 white-screen 의 유발 — 매 ErrorBoundary, global handlers (`window.onerror`, `unhandledrejection`), 매 Sentry-class telemetry 가 필수. 매 2026의 트렌드는 React 19 ErrorBoundary + Sentry + Replay + AI-driven root-cause clustering. ## 매 핵심 ### 매 layers - **Component**: React ErrorBoundary, Vue `errorCaptured`, Svelte ``. - **Async**: try/catch, Promise `.catch`, `unhandledrejection` listener. - **Global**: `window.onerror`, `window.onunhandledrejection`. - **Network**: fetch retry, circuit breaker, AbortController. ### 매 telemetry 기둥 - Capture (stack, breadcrumb, source map). - Group (fingerprint, dedup). - Alert (threshold, regression). - Replay (Sentry / LogRocket — DOM reconstruction). ### 매 응용 1. SPA route-level boundary — 매 chunk load fail 의 reload prompt. 2. Form submission retry with exponential backoff. 3. Feature flag fallback when remote config unavailable. 4. Service Worker offline shell. ## 💻 패턴 ### 1. React ErrorBoundary (class) ```typescript import { Component, type ReactNode } from 'react'; interface State { error?: Error } export class ErrorBoundary extends Component<{ fallback: ReactNode; children: ReactNode }, State> { state: State = {}; static getDerivedStateFromError(error: Error): State { return { error }; } componentDidCatch(error: Error, info: React.ErrorInfo) { Sentry.captureException(error, { extra: { componentStack: info.componentStack } }); } render() { return this.state.error ? this.props.fallback : this.props.children; } } ``` ### 2. react-error-boundary (functional) ```typescript import { ErrorBoundary } from 'react-error-boundary'; (

Failed: {error.message}

)} onReset={() => location.reload()} >
``` ### 3. Global handlers ```typescript window.addEventListener('error', (e) => { Sentry.captureException(e.error ?? new Error(e.message)); }); window.addEventListener('unhandledrejection', (e) => { Sentry.captureException(e.reason); }); ``` ### 4. Chunk load failure recovery ```typescript const lazyWithRetry = (load: () => Promise<{ default: T }>) => React.lazy(async () => { try { return await load(); } catch (err) { if (!sessionStorage.getItem('chunk-retried')) { sessionStorage.setItem('chunk-retried', '1'); location.reload(); } throw err; } }); ``` ### 5. Fetch retry with backoff ```typescript async function fetchRetry(url: string, retries = 3, delay = 500): Promise { try { const res = await fetch(url); if (!res.ok && res.status >= 500) throw new Error(`HTTP ${res.status}`); return res; } catch (err) { if (retries === 0) throw err; await new Promise((r) => setTimeout(r, delay)); return fetchRetry(url, retries - 1, delay * 2); } } ``` ### 6. AbortController on unmount ```typescript useEffect(() => { const ac = new AbortController(); fetch('/api/x', { signal: ac.signal }).catch((e) => { if (e.name !== 'AbortError') report(e); }); return () => ac.abort(); }, []); ``` ### 7. Sentry init (2026) ```typescript import * as Sentry from '@sentry/react'; Sentry.init({ dsn: import.meta.env.VITE_SENTRY_DSN, integrations: [ Sentry.browserTracingIntegration(), Sentry.replayIntegration({ maskAllText: false }), ], tracesSampleRate: 0.1, replaysOnErrorSampleRate: 1.0, release: import.meta.env.VITE_RELEASE, }); ``` ### 8. Vue 3 errorHandler ```typescript import { createApp } from 'vue'; const app = createApp(App); app.config.errorHandler = (err, instance, info) => { Sentry.captureException(err, { extra: { info } }); }; ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Component-local fail | ErrorBoundary at route level. | | Async fail | try/catch + telemetry. | | Chunk 404 (deploy mid-session) | lazyWithRetry + reload. | | Transient 5xx | Exponential backoff retry. | | Auth expired | Refresh token interceptor. | **기본값**: Sentry + Replay + per-route ErrorBoundary + global handlers. ## 🔗 Graph - 부모: [[Observability]] - 변형: [[Circuit Breaker]] - 응용: [[Sentry]] · [[Logrocket]] - Adjacent: [[Source Maps]] · [[Feature Flags]] ## 🤖 LLM 활용 **언제**: ErrorBoundary scaffolding, retry helper 작성, Sentry config. **언제 X**: 매 root-cause analysis from minified stack — 매 source map upload 필수. ## ❌ 안티패턴 - **Swallow errors**: 매 `catch {}` 빈 — 매 silent fail. - **No source map**: 매 prod stack 의 `a.b.c` — 매 debug X. - **Boundary at root only**: 매 한 component fail이 매 entire app crash. - **Console.error as monitoring**: 매 user 의 console 의 도달 X — telemetry 필수. ## 🧪 검증 / 중복 - Verified (Sentry docs, react.dev error boundary). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Error boundary + Sentry 2026 patterns |