# Error Handling Guide This guide covers ThrillWiki's comprehensive error handling system for both the Django backend and Nuxt frontend. ## Overview The error system captures errors from all sources (frontend, backend, API) and displays them in the admin dashboard at `/admin/errors`. --- ## Quick Start ### Backend (Python) ```python from apps.core.utils import capture_errors, error_context, capture_and_log # Option 1: Decorator on functions/views @capture_errors(severity='high') def create_park(request, data): return ParkService.create(data) # Errors auto-captured # Option 2: Context manager for code blocks with error_context('Processing payment', severity='critical'): process_payment() # Option 3: Manual capture try: risky_operation() except Exception as e: error_id = capture_and_log(e, 'Risky operation failed') return Response({'error': f'Failed (ref: {error_id})'}) ``` ### Frontend (TypeScript) ```typescript // Option 1: useErrorBoundary composable const { wrap, error, isError, retry } = useErrorBoundary({ componentName: 'RideDetail' }) const ride = await wrap(() => api.get('/rides/1'), 'Loading ride') // Option 2: tryCatch utility (Go-style) const [data, err] = await tryCatch(fetchRide(id), 'Fetching ride') if (err) return // Error already reported // Option 3: useReportError (manual) const { reportError } = useReportError() try { await riskyOperation() } catch (e) { reportError(e, { action: 'Risky operation' }) } ``` --- ## Backend Utilities ### `@capture_errors` Decorator Automatically captures exceptions from decorated functions. ```python from apps.core.utils import capture_errors @capture_errors( source='api', # 'frontend', 'backend', or 'api' severity='high', # 'critical', 'high', 'medium', 'low' reraise=True, # Re-raise after capturing (default True) log_errors=True # Also log to Python logger (default True) ) def my_view(request): # If this raises, error is automatically captured return do_something() ``` **Use for**: API views, service methods, any function where you want automatic tracking. ### `error_context` Context Manager Captures errors from a code block with rich context. ```python from apps.core.utils import error_context with error_context( 'Creating ride submission', source='backend', severity='high', request=request, # Optional: for user/IP context entity_type='Ride', # Optional: what entity entity_id=123, # Optional: which entity reraise=True # Default True ): submission = SubmissionService.create(data) ``` **Use for**: Specific operations where you want detailed context about what was happening. ### `capture_and_log` Function One-liner for manual error capture that returns the error ID. ```python from apps.core.utils import capture_and_log try: result = risky_operation() except Exception as e: error_id = capture_and_log( e, 'Risky operation', severity='high', request=request, entity_type='Park', entity_id=42 ) return Response({'error': f'Failed (ref: {error_id})'}, status=500) ``` **Use for**: When you need the error ID to show to users for support reference. --- ## Frontend Utilities ### `useErrorBoundary` Composable Component-level error boundary with retry support. ```typescript const { error, // Ref - current error isError, // ComputedRef - whether error exists lastErrorId, // Ref - for support reference clear, // () => void - clear error state retry, // () => Promise - retry last operation wrap, // Wrap async function wrapSync // Wrap sync function } = useErrorBoundary({ componentName: 'MyComponent', entityType: 'Ride', defaultSeverity: 'medium', showToast: true, onError: (err, id) => console.log('Error:', err) }) // In template //
// {{ error?.message }} // //
``` ### `tryCatch` Utility Go-style error handling for one-liners. ```typescript import { tryCatch, tryCatchSync } from '~/utils/tryCatch' // Async const [ride, error] = await tryCatch(api.get('/rides/1'), 'Loading ride') if (error) { console.log('Failed:', error.message) return } console.log('Got ride:', ride) // Sync const [data, err] = tryCatchSync(() => JSON.parse(input), 'Parsing JSON') // With options const [data, err] = await tryCatch(fetchData(), 'Fetching', { severity: 'critical', silent: true, // No toast notification entityType: 'Ride', entityId: 123 }) ``` ### `useReportError` Composable Full-featured error reporting with maximum context. ```typescript const { reportError, reportErrorSilent, withErrorReporting } = useReportError() // Report with toast await reportError(error, { action: 'Saving ride', componentName: 'EditRideModal', entityType: 'Ride', entityId: 42, severity: 'high', metadata: { custom: 'data' } }) // Report without toast await reportErrorSilent(error, { action: 'Background task' }) // Wrap a function const safeFetch = withErrorReporting(fetchRide, { componentName: 'RideDetail', entityType: 'Ride' }) ``` ### Global Error Plugin The `errorPlugin.client.ts` automatically catches: - Vue component errors - Unhandled promise rejections - Global JavaScript errors These are reported silently to the dashboard without user intervention. --- ## Viewing Errors 1. Navigate to `/admin/errors` (requires admin role) 2. Filter by severity, source, date range, or resolution status 3. Click on an error to see full details including: - Stack trace - Browser environment - User context - Request details 4. Mark errors as resolved with notes 5. Export errors to CSV --- ## Best Practices 1. **Use decorators for views**: All API viewsets should have `@capture_errors` 2. **Use context managers for critical operations**: Payments, data migrations, bulk operations 3. **Use `tryCatch` for async code**: Clean, Go-style error handling 4. **Set appropriate severity**: - `critical`: Database errors, payment failures, data loss - `high`: Unexpected runtime errors, 5xx responses - `medium`: Validation errors, user input issues - `low`: Warnings, graceful degradation 5. **Include entity context**: Always provide `entity_type` and `entity_id` when operating on specific records 6. **Don't swallow errors**: Use `reraise=True` (default) unless you have a recovery strategy --- ## Integration Patterns ### API ViewSet with Decorator ```python from rest_framework import viewsets from apps.core.utils import capture_errors class RideViewSet(viewsets.ModelViewSet): @capture_errors(source='api') def create(self, request, *args, **kwargs): return super().create(request, *args, **kwargs) ``` ### Vue Component with Error Boundary ```vue ``` --- ## Troubleshooting **Errors not appearing in dashboard?** - Check the backend server logs for capture failures - Verify `MIDDLEWARE` includes `ErrorCaptureMiddleware` - Ensure the `ApplicationError` model is migrated **Frontend errors not reporting?** - Check browser console for API call failures - Verify `.env` has correct `NUXT_PUBLIC_API_BASE` (port 8000) - Check network tab for `/api/v1/errors/report/` requests