--- description: Standards for consistent error handling patterns across frontend and backend globs: **/*.{ts,tsx,js,jsx,go} --- filters: - type: file_extension pattern: "\\.(ts|tsx|js|jsx|go)$" - type: content pattern: "(?s)try|catch|error|err|throw|panic|recover" actions: - type: suggest message: | # Error Handling Standards ## Frontend (TypeScript/JavaScript) 1. Always use typed error handling: ```typescript try { // Operation that might fail } catch (error) { if (error instanceof ApiError) { // Handle API errors } else if (error instanceof ValidationError) { // Handle validation errors } else { // Handle unexpected errors console.error('Unexpected error:', error); } } ``` 2. Define custom error classes: ```typescript class ApplicationError extends Error { constructor(message: string) { super(message); this.name = 'ApplicationError'; } } class ApiError extends ApplicationError { statusCode: number; constructor(message: string, statusCode: number) { super(message); this.name = 'ApiError'; this.statusCode = statusCode; } } ``` 3. For async functions, always use try/catch with async/await: ```typescript async function fetchData() { try { const response = await api.get('/endpoint'); return response.data; } catch (error) { handleError(error); throw error; // Re-throw if needed } } ``` 4. For React components, implement error boundaries: ```tsx import { ErrorBoundary } from 'react-error-boundary'; function ErrorFallback({ error, resetErrorBoundary }) { return (

Something went wrong:

{error.message}
); } function MyComponent() { return ( ); } ``` ## Backend (Go) 1. Return errors rather than using panic: ```go func ProcessData(data []byte) (Result, error) { if len(data) == 0 { return Result{}, errors.New("empty data provided") } // Process data return result, nil } ``` 2. Use error wrapping for context: ```go import "fmt" func FetchUserData(userID string) ([]byte, error) { data, err := database.Query(userID) if err != nil { return nil, fmt.Errorf("fetching user data: %w", err) } return data, nil } ``` 3. Use custom error types for specific cases: ```go type NotFoundError struct { Resource string ID string } func (e NotFoundError) Error() string { return fmt.Sprintf("%s with ID %s not found", e.Resource, e.ID) } // Usage if data == nil { return NotFoundError{Resource: "User", ID: userID} } ``` 4. Check errors immediately: ```go resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() ``` ## General Principles 1. Log errors appropriately: - Debug: For development information - Info: For tracking normal operation - Warn: For potential issues - Error: For actual errors affecting operation - Fatal: For errors requiring application shutdown 2. Don't expose system errors to users: - Log the technical details - Return user-friendly messages 3. Include contextual information: - What operation was being performed - What resources were involved - Any IDs or references that help identify the context 4. Handle all error cases - never silently ignore errors metadata: priority: high version: 1.0
examples: - input: | // Bad: Untyped error handling try { const data = await fetchData(); } catch (error) { console.log(error); } output: | // Good: Typed error handling with proper logging and user feedback try { const data = await fetchData(); } catch (error) { if (error instanceof ApiError) { toast.error('Could not connect to the server. Please try again later.'); logger.error('API Error:', { error, endpoint: '/api/data' }); } else { toast.error('An unexpected error occurred.'); logger.error('Unexpected error:', { error }); } } - input: | // Bad: No error handling in Go function func GetUser(id string) User { data := db.Find(id) return User{Name: data.Name, Email: data.Email} } output: | // Good: Proper error handling and propagation func GetUser(id string) (User, error) { data, err := db.Find(id) if err != nil { return User{}, fmt.Errorf("failed to find user %s: %w", id, err) } return User{Name: data.Name, Email: data.Email}, nil }