| name | audit-error-ux |
| description | Audit error handling UX — error boundaries, silent failures, loading states, empty states |
| user-invocable | true |
Audit: Error UX & Resilience
Audit how errors and edge cases surface to the user. This is a research-only audit — do not modify any code.
What to Search For
Error Boundaries
Find React error boundaries (ErrorBoundary components or componentDidCatch):
Silent Failures
Find operations that can fail without any user feedback:
What to check: Would the user know something went wrong? If not, flag it.
Error Message Quality
Beyond whether an error surfaces, audit what it says:
- Generic messages that discard actual error: Look for render paths that show a hardcoded string while an actual error string sits unused in state. Common pattern:
if (someStore.errorMessage) {
return <p>Something went wrong.</p>;
}
Grep:
grep -rn "File not found\|Something went wrong\|An error occurred" src/components/ --include="*.tsx"
For each hit, check whether the actual error string from state is displayed (even in small text-xs text-muted-foreground font-mono text below the friendly message). If the error string is available and not shown at all, flag as Low (misleading diagnosis wastes user time). (e.g. an editor that stores the full Tauri error in loadError but always renders the hardcoded "File not found" regardless of the actual cause.)
- The correct pattern shows the friendly message + the raw error in subdued mono text:
<p>Could not open file</p>
<p className="text-xs text-muted-foreground font-mono mt-1">{activeTab.loadError}</p>
Loading States
Find async operations and check if they show loading indicators:
-
File tree loading — is there a skeleton or spinner while list_directory runs?
-
AI chat responses — is there a typing indicator while waiting for the first token?
-
Model downloads — is progress shown?
-
Settings that require async validation — does the UI indicate "checking..."?
-
Loading indicators must be announced: A spinner or skeleton loader (Loader2 animate-spin) that has no aria-live region or aria-label is invisible to screen readers. When a load state starts, an aria-live="polite" region should announce "Loading..." and when complete should announce the result or clear. At minimum, the button or container that entered the loading state should expose aria-busy="true" while loading.
Grep for unannounced loading:
grep -rn "Loader2\|animate-spin\|isLoading\|loading" src/components/ --include="*.tsx" | grep -v "aria-label\|aria-live\|aria-busy"
Flag any loading state on a user-triggered action (button click, form submit) that has no accessible loading announcement as Low severity.
Empty States
Check views for what they show when data is absent:
- File tree with no folders open — helpful message or blank?
- Chat panel with no messages — onboarding prompt or empty?
- Search results with no matches — "no results" message or blank?
- Settings with no connections configured — guidance or empty list?
- Activity panel with no tasks — message or blank?
Graceful Degradation
Check what happens under failure conditions:
- AI provider is unreachable — does the chat show an error or hang?
- Ollama is not running — clear message or cryptic error?
- Network is offline — does the app still function for local editing?
- File on disk is deleted while open in editor — handled or crash?
- localStorage is full — does persist middleware handle the error?
Crash Recovery
- What state is lost on app crash? (undo history, unsaved changes, chat messages)
- App startup with corrupt persisted state:
Output Format
For each finding:
### <SEVERITY>: <Short title>
**File:** `<path>:<line>`
<What the user experiences and why it's bad.>
**Fix:** <How to improve the user experience.>
End with a ### Confirmed Good Patterns section.
Example Finding
MEDIUM: AI provider error shows raw error string
File: src/hooks/useAIOperations.ts:312
When an AI API call fails, the raw error string from Rust is shown in a toast: "Failed to connect to api.anthropic.com: connection refused". This is confusing for non-technical users.
Fix: Map common errors to user-friendly messages:
- Connection refused → "Could not reach [provider]. Check your internet connection."
- 401 → "Invalid API key. Check your settings."
- 429 → "Rate limited. Please wait a moment and try again."