# Frontend Error Handling Anti-Patterns # Patterns that hide errors or fail to provide user feedback name: Error Handling description: | Detects patterns where errors are silently swallowed, promises unhandled, or users left without feedback when operations fail. These patterns lead to confusing UX and hard-to-debug issues. patterns: - id: unhandled-promise description: Async function called without await or .catch() grep_pattern: '^\s+\w+\([^)]*\)\s*$' file_glob: '*.{vue,ts}' context_lines: 3 verdict_hints: ISSUE_IF: "Async function (fetch, API call) with no error handling" OK_IF: "Sync function; or fire-and-forget with documented reason" - id: empty-catch-block description: Catch block that does nothing with the error grep_pattern: 'catch\s*\([^)]*\)\s*\{\s*\}' file_glob: '*.{vue,ts}' context_lines: 3 verdict_hints: ISSUE_IF: "Error completely swallowed - user gets no feedback" OK_IF: "Never OK - at minimum log or set error state" - id: catch-only-console description: Catch block that only logs to console grep_pattern: 'catch.*\{[\s\n]*console\.(log|error|warn)' multiline: true file_glob: '*.{vue,ts}' context_lines: 5 verdict_hints: ISSUE_IF: "Error logged but UI shows success/no feedback to user" OK_IF: "Also sets error state or shows toast notification" - id: fetch-no-error-check description: Fetch without checking response.ok grep_pattern: 'fetch\([^)]+\)[\s\S]*?\.json\(\)' multiline: true file_glob: '*.{vue,ts}' context_lines: 7 verdict_hints: ISSUE_IF: "Response not checked for errors before parsing JSON" OK_IF: "Uses wrapper that handles errors; or response.ok checked" - id: missing-loading-state description: Async operation without loading indicator grep_pattern: 'async.*\{[\s\S]*?await.*fetch' multiline: true file_glob: '*.vue' context_lines: 10 verdict_hints: ISSUE_IF: "No isLoading ref set before/after async operation" OK_IF: "Loading state managed by composable; or instant operation" - id: missing-error-state description: API call without error state handling grep_pattern: 'await.*(fetch|api|axios)' file_glob: '*.vue' context_lines: 8 verdict_hints: ISSUE_IF: "No error ref or error handling visible in component" OK_IF: "Error handling in composable; or uses error boundary" - id: silent-store-action description: Store action that catches but doesn't surface errors grep_pattern: 'catch.*\{[\s\S]*?return (false|null|undefined|\[\]|\{\})' multiline: true file_glob: 'stores/*.ts' context_lines: 6 verdict_hints: ISSUE_IF: "Store swallows error, returns falsy - caller can't show error" OK_IF: "Also sets store.error state that UI can display" - id: onmounted-no-error-handling description: onMounted with async call but no error handling grep_pattern: 'onMounted\(\s*async' file_glob: '*.vue' context_lines: 10 verdict_hints: ISSUE_IF: "Async onMounted without try/catch - errors crash silently" OK_IF: "Has try/catch with error state; or uses error boundary" - id: watch-async-no-catch description: Watch callback with async but no error handling grep_pattern: 'watch\([^)]+,\s*async' file_glob: '*.vue' context_lines: 8 verdict_hints: ISSUE_IF: "Async watch without error handling" OK_IF: "Has try/catch; or errors handled by called function" - id: socket-no-error-handler description: Socket.io without error event handler grep_pattern: 'socket\.(on|emit)\(' file_glob: '*.{vue,ts}' context_lines: 10 verdict_hints: ISSUE_IF: "Socket used without socket.on('error') or socket.on('connect_error')" OK_IF: "Error handlers registered elsewhere (socket setup file)"