# Error Display Strategy

**Date**: 2025-01-27  
**Action**: 3.1.1.5 - Create error display strategy document  
**Status**: ✅ Complete

## Overview

This document defines the strategy for when to use `toast.error()` vs `ErrorDisplay` component for error presentation across the application. This strategy ensures consistent, user-friendly error handling while maintaining appropriate UX patterns for different error types.

## Core Principles

1. **Persistent errors** → Use `ErrorDisplay` (user needs to see and potentially act on the error)
2. **Transient errors** → Use `toast.error()` (quick feedback for temporary actions)
3. **Form validation** → Keep inline validation errors (field-level feedback)
4. **Critical errors** → Use `ErrorDisplay` with retry capability
5. **User action errors** → Use `ErrorDisplay` banner (dismissible, contextual)

## Decision Tree

```
Is the error related to form validation?
├─ YES → Use inline validation error (text-red-500, keep existing pattern)
└─ NO → Continue

Is the error from a query (data fetching)?
├─ YES → Use ErrorDisplay card/inline variant with retry
└─ NO → Continue

Is the error from a mutation (data update)?
├─ YES → Use ErrorDisplay banner variant (dismissible)
└─ NO → Continue

Is the error from a quick action (copy link, quick toggle)?
├─ YES → Use toast.error() (transient feedback)
└─ NO → Continue

Is the error critical (network failure, auth failure, runtime crash)?
├─ YES → Use ErrorDisplay with appropriate variant and retry
└─ NO → Use toast.error() as fallback
```

## ErrorDisplay Usage Guidelines

### When to Use ErrorDisplay

#### 1. Query Errors (Data Fetching)

**Use**: `ErrorDisplay` card or inline variant  
**Variant**: `card` for page-level errors, `inline` for component-level errors  
**Features**: Retry button, error details (dev mode)  
**Examples**:

- Failed to load tracks/library
- Failed to load playlist details
- Failed to load user profile
- Failed to load marketplace items

```tsx
{
  isError && (
    <ErrorDisplay
      error={error}
      variant="card"
      severity="error"
      context={{ action: 'fetching tracks', resource: 'tracks' }}
      onRetry={() => refetch()}
    />
  );
}
```

#### 2. Mutation Errors (Data Updates)

**Use**: `ErrorDisplay` banner variant  
**Variant**: `banner` (dismissible, appears at top of page/content)  
**Features**: Dismiss button, contextual error message  
**Examples**:

- Failed to add track to playlist
- Failed to update profile
- Failed to delete resource
- Failed to share resource

```tsx
{
  mutationError && (
    <ErrorDisplay
      error={mutationError}
      variant="banner"
      severity="error"
      onDismiss={() => setMutationError(null)}
    />
  );
}
```

#### 3. Network Errors (API Failures)

**Use**: `ErrorDisplay` banner variant  
**Variant**: `banner` or `card` depending on context  
**Features**: Retry button, network-specific messaging  
**Examples**:

- Connection timeout
- Server unavailable
- Network request failed

```tsx
<ErrorDisplay
  error={networkError}
  variant="banner"
  severity="error"
  context={{ action: 'connecting to server', resource: 'api' }}
  onRetry={() => retryRequest()}
/>
```

#### 4. Runtime Errors (Component Crashes)

**Use**: `ErrorDisplay` in ErrorBoundary fallback  
**Variant**: `card` or `modal`  
**Features**: Error details, reload page action  
**Examples**:

- Component render error
- Unhandled exception
- React error boundary catch

```tsx
<ErrorBoundary
  fallback={
    <ErrorDisplay
      error={error}
      variant="card"
      severity="error"
      actions={[
        { label: 'Reload Page', onClick: () => window.location.reload() },
      ]}
    />
  }
>
  {children}
</ErrorBoundary>
```

#### 5. Auth Errors (Authentication Failures)

**Use**: `ErrorDisplay` inline variant  
**Variant**: `inline`  
**Features**: Contextual auth error message  
**Examples**:

- Login failed
- Session expired
- Unauthorized access

```tsx
<ErrorDisplay
  error={authError}
  variant="inline"
  severity="error"
  context={{ action: 'authenticating', resource: 'auth' }}
/>
```

#### 6. Player Errors (Audio Playback)

**Use**: `ErrorDisplay` card variant  
**Variant**: `card`  
**Features**: Retry button, error type detection  
**Examples**:

- Audio decode error
- Network error during playback
- Source file not found

```tsx
<ErrorDisplay
  error={playerError}
  variant="card"
  severity="error"
  context={{ action: 'playing audio', resource: 'player' }}
  onRetry={() => retryPlayback()}
/>
```

### When NOT to Use ErrorDisplay

#### 1. Form Validation Errors

**Use**: Inline validation errors (existing pattern)  
**Reason**: Field-level feedback is more appropriate  
**Pattern**: Keep existing `text-red-500` inline errors

```tsx
// ✅ Keep this pattern
{
  errors.field && (
    <p className="text-sm text-red-500">{errors.field.message}</p>
  );
}
```

#### 2. Quick Action Errors (Transient)

**Use**: `toast.error()`  
**Reason**: Quick feedback for temporary actions  
**Examples**:

- Copy link to clipboard
- Quick toggle actions
- Temporary state changes

```tsx
// ✅ Keep toast for quick actions
try {
  await navigator.clipboard.writeText(link);
  toast.success('Link copied');
} catch {
  toast.error('Failed to copy link');
}
```

#### 3. Validation Messages (Non-Critical)

**Use**: `toast.error()` or inline validation  
**Reason**: User input validation feedback  
**Examples**:

- "Username is required"
- "Please type DELETE to confirm"
- "Cart is empty"

```tsx
// ✅ Keep toast for validation messages
if (!username) {
  toast.error('Username is required');
  return;
}
```

## Variant Selection Guide

### `inline` Variant

**Use when**:

- Error is contextual to a specific component
- Error appears within content flow
- Error doesn't need to interrupt user flow

**Examples**:

- Form submission errors
- Component-level query errors
- Inline validation errors (if not using form validation pattern)

### `banner` Variant

**Use when**:

- Error affects page-level functionality
- Error is dismissible
- Error should be prominent but not blocking

**Examples**:

- Mutation errors (add/update/delete)
- Network errors
- Session expiration warnings

### `card` Variant

**Use when**:

- Error replaces main content
- Error needs visual prominence
- Error is part of content layout

**Examples**:

- Query errors (no data to show)
- Player errors (replaces player UI)
- Profile load errors

### `modal` Variant

**Use when**:

- Error is critical and blocking
- User must acknowledge error
- Error requires immediate attention

**Examples**:

- Critical system errors
- Payment failures
- Security violations

## Severity Selection Guide

### `error` Severity (Default)

**Use when**:

- Operation failed
- Data cannot be loaded
- Action cannot be completed

**Visual**: Red colors, AlertCircle icon

### `warning` Severity

**Use when**:

- Operation partially succeeded
- Warning that doesn't block functionality
- User should be aware but can continue

**Visual**: Yellow/gold colors, AlertTriangle icon

### `info` Severity

**Use when**:

- Informational message
- Non-critical notification
- Helpful context

**Visual**: Cyan colors, Info icon

## Migration Strategy

### Phase 1: Query Errors (HIGH Priority)

1. Replace query error displays with ErrorDisplay card variant
2. Add retry functionality
3. Files: LibraryPage ✅, TrackDetailPage, MarketplaceHome, RolesPage, SettingsPage

### Phase 2: Mutation Errors (MEDIUM Priority)

1. Replace mutation toast.errors with ErrorDisplay banner variant
2. Add dismiss functionality
3. Files: All feature files with mutations

### Phase 3: Component Errors (MEDIUM Priority)

1. Replace PlayerError with ErrorDisplay card variant
2. Replace AuthErrorMessage with ErrorDisplay inline variant
3. Update ErrorBoundary fallback UI

### Phase 4: Network Errors (HIGH Priority)

1. Replace API client toast.errors with ErrorDisplay banner
2. Add retry functionality
3. File: api/client.ts

### Phase 5: Keep Toast for Transient Actions (LOW Priority)

1. Keep toast.error() for copy link, quick actions
2. Document exceptions
3. No changes needed

## Code Examples

### Query Error Pattern

```tsx
const { data, isError, error, refetch } = useQuery({
  queryKey: ['tracks'],
  queryFn: fetchTracks,
});

return (
  <>
    {isError ? (
      <ErrorDisplay
        error={error}
        variant="card"
        severity="error"
        context={{ action: 'fetching tracks', resource: 'tracks' }}
        onRetry={() => refetch()}
      />
    ) : (
      <TrackList tracks={data} />
    )}
  </>
);
```

### Mutation Error Pattern

```tsx
const [mutationError, setMutationError] = useState<Error | null>(null);

const handleMutation = async () => {
  try {
    setMutationError(null);
    await mutateAsync(data);
    toast.success('Success');
  } catch (error) {
    const apiError = parseApiError(error);
    setMutationError(new Error(apiError.message));
  }
};

return (
  <>
    {mutationError && (
      <ErrorDisplay
        error={mutationError}
        variant="banner"
        severity="error"
        onDismiss={() => setMutationError(null)}
      />
    )}
    <Form onSubmit={handleMutation} />
  </>
);
```

### Form Validation Pattern (Keep)

```tsx
// ✅ Keep existing pattern for form validation
<FormField label="Email" error={errors.email?.message}>
  <Input type="email" {...register('email')} />
</FormField>
```

### Quick Action Pattern (Keep Toast)

```tsx
// ✅ Keep toast for quick actions
const handleCopyLink = async () => {
  try {
    await navigator.clipboard.writeText(link);
    toast.success('Link copied');
  } catch {
    toast.error('Failed to copy link');
  }
};
```

## Accessibility Considerations

### ErrorDisplay Component

- ✅ ARIA `role="alert"` and `aria-live="polite"`
- ✅ Keyboard navigation for retry/dismiss buttons
- ✅ Screen reader announcements
- ✅ Focus management

### Toast Notifications

- ✅ ARIA live regions (handled by toast library)
- ✅ Auto-dismiss with appropriate timing
- ✅ Keyboard accessible

### Form Validation

- ✅ Inline errors associated with form fields
- ✅ ARIA `aria-invalid` and `aria-describedby`
- ✅ Screen reader announcements

## Testing Strategy

1. **Query Errors**: Test retry functionality
2. **Mutation Errors**: Test dismiss functionality
3. **Network Errors**: Test retry and offline handling
4. **Form Validation**: Test inline error display
5. **Toast Errors**: Test transient error display

## Rollback Plan

If ErrorDisplay causes issues:

1. Revert to toast.error() for affected areas
2. Keep ErrorDisplay for query errors (most critical)
3. Gradually reintroduce ErrorDisplay for mutations

## References

- [ErrorDisplay Component API](./ERROR_DISPLAY_COMPONENT_API.md)
- [Error Display Patterns Audit](../../docs/ERROR_DISPLAY_PATTERNS_AUDIT.md)
- [Error Messages Utility](../../utils/errorMessages.ts)
- [API Error Handler](../../utils/apiErrorHandler.ts)
