# handle_errors > Handle API and UI errors gracefully using error boundaries, toast notifications, and Claude code for error orchestration. Use this skill whenever an error occurs in frontend or backend calls to ensure proper error handling and user experience. - Author: Zahida Raees - Repository: zahidaraees/hackathon-ii-phase-ii-Full-Stack-Web-Application - Version: 20260207224919 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-07 - Source: https://github.com/zahidaraees/hackathon-ii-phase-ii-Full-Stack-Web-Application - Web: https://mule.run/skillshub/@@zahidaraees/hackathon-ii-phase-ii-Full-Stack-Web-Application~handle_errors:20260207224919 --- --- name: handle_errors description: Handle API and UI errors gracefully using error boundaries, toast notifications, and Claude code for error orchestration. Use this skill whenever an error occurs in frontend or backend calls to ensure proper error handling and user experience. license: Complete terms in LICENSE.txt --- # Handle Errors Skill This skill provides a comprehensive error handling solution for both API and UI errors in a Next.js application. ## Purpose Handle API and UI errors gracefully to provide a better user experience and prevent application crashes. This skill manages error boundaries, displays informative notifications, and orchestrates error handling using Claude code. ## When to Use Use this skill whenever an error occurs in frontend or backend calls. This includes: - API request failures - Network connectivity issues - Invalid user inputs - Server-side errors - Component rendering errors - Unhandled exceptions in the application ## Implementation Overview The error handling is implemented using: - Error boundaries for catching component-level errors - Toast notifications for displaying error messages - Claude code for error orchestration and categorization ## Detailed Implementation ### 1. Error Boundary Component Create an error boundary component to catch JavaScript errors anywhere in the child component tree: ```jsx // components/ErrorBoundary.jsx import React from 'react'; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null, errorInfo: null }; } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI return { hasError: true }; } componentDidCatch(error, errorInfo) { // Log the error to an error reporting service console.error('Error caught by boundary:', error, errorInfo); this.setState({ error: error, errorInfo: errorInfo }); // Send error to error reporting service this.reportError(error, errorInfo); } reportError = (error, errorInfo) => { // Send error to your error reporting service (e.g., Sentry, LogRocket) if (process.env.NODE_ENV === 'production') { // Example: Report to external service // ErrorReportingService.captureException(error, { errorInfo }); } }; render() { if (this.state.hasError) { // You can render any custom fallback UI return (

Something went wrong

Error: {this.state.error?.toString()}

More details
                {this.state.errorInfo?.componentStack}
              
); } return this.props.children; } } export default ErrorBoundary; ``` ### 2. Global Error Handler Create a global error handler for unhandled errors: ```javascript // utils/globalErrorHandler.js import { showErrorToast } from './toastNotifications'; // Handle uncaught errors if (typeof window !== 'undefined') { window.addEventListener('error', (event) => { console.error('Global error:', event.error); showErrorToast('An unexpected error occurred. Please try again.'); // Report to error tracking service reportError(event.error, { type: 'global-error', message: event.error.message, filename: event.filename, lineno: event.lineno, colno: event.colno }); }); // Handle unhandled promise rejections window.addEventListener('unhandledrejection', (event) => { console.error('Unhandled promise rejection:', event.reason); showErrorToast('An unexpected error occurred. Please try again.'); // Report to error tracking service reportError(event.reason, { type: 'unhandled-rejection', reason: event.reason }); }); } // Server-side error handler for Next.js API routes export function handleApiError(res, error, defaultMessage = 'Internal server error') { console.error('API Error:', error); // Determine error status based on error type let statusCode = 500; if (error.statusCode) { statusCode = error.statusCode; } else if (error.name === 'ValidationError') { statusCode = 400; } else if (error.name === 'UnauthorizedError') { statusCode = 401; } else if (error.name === 'NotFoundError') { statusCode = 404; } // Send appropriate response res.status(statusCode).json({ error: true, message: error.message || defaultMessage, ...(process.env.NODE_ENV === 'development' && { stack: error.stack }) }); // Report to error tracking service reportError(error, { type: 'api-error', statusCode, url: res.req.url }); } // Generic error reporting function function reportError(error, context = {}) { if (process.env.NODE_ENV === 'production') { // Send error to external error tracking service // Example: Sentry.captureException(error, { contexts: context }); } // Log error locally for debugging console.error('Reported error:', error, context); } ``` ### 3. Toast Notifications System Set up toast notifications for displaying error messages to users: ```jsx // components/ToastProvider.jsx import React, { createContext, useContext, useState, useCallback } from 'react'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; // Create context for toast notifications const ToastContext = createContext(); // Toast provider component export const ToastProvider = ({ children }) => { const [toasts, setToasts] = useState([]); const showToast = useCallback((type, message, options = {}) => { const id = Date.now().toString(); const newToast = { id, type, message, ...options }; setToasts(prev => [...prev, newToast]); // Auto-remove toast after delay setTimeout(() => { setToasts(prev => prev.filter(toast => toast.id !== id)); }, options.duration || 5000); }, []); const showError = useCallback((message, options = {}) => { showToast('error', message, { ...options, type: 'error' }); }, [showToast]); const showSuccess = useCallback((message, options = {}) => { showToast('success', message, { ...options, type: 'success' }); }, [showToast]); const showWarning = useCallback((message, options = {}) => { showToast('warning', message, { ...options, type: 'warning' }); }, [showToast]); const showInfo = useCallback((message, options = {}) => { showToast('info', message, { ...options, type: 'info' }); }, [showToast]); const value = { showError, showSuccess, showWarning, showInfo }; return ( {children} ); }; // Custom hook to use toast notifications export const useToast = () => { const context = useContext(ToastContext); if (!context) { throw new Error('useToast must be used within a ToastProvider'); } return context; }; // Alternative implementation using react-toastify directly export const showErrorToast = (message, options = {}) => { toast.error(message, { position: "top-right", autoClose: options.autoClose || 5000, hideProgressBar: false, closeOnClick: true, pauseOnHover: true, draggable: true, progress: undefined, ...options }); }; export const showSuccessToast = (message, options = {}) => { toast.success(message, { position: "top-right", autoClose: options.autoClose || 5000, hideProgressBar: false, closeOnClick: true, pauseOnHover: true, draggable: true, progress: undefined, ...options }); }; export const showWarningToast = (message, options = {}) => { toast.warn(message, { position: "top-right", autoClose: options.autoClose || 5000, hideProgressBar: false, closeOnClick: true, pauseOnHover: true, draggable: true, progress: undefined, ...options }); }; export const showInfoToast = (message, options = {}) => { toast.info(message, { position: "top-right", autoClose: options.autoClose || 5000, hideProgressBar: false, closeOnClick: true, pauseOnHover: true, draggable: true, progress: undefined, ...options }); }; ``` ### 4. Error Handling Hook Create a custom hook for handling errors in components: ```javascript // hooks/useErrorHandler.js import { useCallback } from 'react'; import { showErrorToast, showWarningToast, showInfoToast } from '../components/ToastProvider'; export const useErrorHandler = () => { const handleError = useCallback((error, context = '') => { console.error(`${context ? context + ': ' : ''}${error.message || error}`); // Categorize and handle different types of errors if (error.response) { // Client received an error response (4xx, 5xx) const status = error.response.status; switch (status) { case 400: showErrorToast('Bad request. Please check your input and try again.'); break; case 401: showErrorToast('Unauthorized. Please log in and try again.'); // Optionally redirect to login if (typeof window !== 'undefined') { window.location.href = '/login'; } break; case 403: showErrorToast('Access forbidden. You do not have permission to perform this action.'); break; case 404: showErrorToast('Resource not found. The requested item may have been removed.'); break; case 429: showWarningToast('Too many requests. Please slow down and try again later.'); break; case 500: showErrorToast('Server error. Please try again later.'); break; default: showErrorToast(`Request failed with status ${status}. Please try again.`); } } else if (error.request) { // Request was made but no response received showErrorToast('Network error. Please check your connection and try again.'); } else { // Something else happened showErrorToast(error.message || 'An unexpected error occurred.'); } }, []); return { handleError }; }; // Example usage in a component /* import { useErrorHandler } from '../hooks/useErrorHandler'; const MyComponent = () => { const { handleError } = useErrorHandler(); const fetchData = async () => { try { const response = await api.get('/some-endpoint'); // Handle successful response } catch (error) { handleError(error, 'Fetching data'); } }; return (
); }; */ ``` ### 5. Claude Code for Error Orchestration The following Claude-enhanced code provides intelligent error categorization and handling: ```javascript // utils/errorOrchestrator.js import { showErrorToast, showWarningToast, showInfoToast, showSuccessToast } from '../components/ToastProvider'; import { reportError } from './globalErrorHandler'; // Define error categories and their handlers const ERROR_CATEGORIES = { AUTHENTICATION: { codes: ['UNAUTHORIZED', 'TOKEN_EXPIRED', 'INVALID_TOKEN'], handler: (error) => { showErrorToast('Authentication failed. Please log in again.'); // Redirect to login if (typeof window !== 'undefined') { window.location.href = '/login'; } } }, VALIDATION: { codes: ['VALIDATION_ERROR', 'INVALID_INPUT'], handler: (error) => { showErrorToast(error.details || 'Invalid input provided. Please check your data.'); } }, NETWORK: { codes: ['NETWORK_ERROR', 'CONNECTION_TIMEOUT'], handler: (error) => { showErrorToast('Network error. Please check your connection and try again.'); } }, SERVER: { codes: ['SERVER_ERROR', 'INTERNAL_ERROR'], handler: (error) => { showErrorToast('Server error. Our team has been notified. Please try again later.'); } }, BUSINESS_LOGIC: { codes: ['INSUFFICIENT_FUNDS', 'QUOTA_EXCEEDED'], handler: (error) => { showWarningToast(error.message || 'Operation could not be completed due to business rules.'); } } }; // Main error orchestration function export const orchestrateError = (error, context = {}) => { // Log the error for debugging console.error('Orchestrated error:', error, context); // Determine error category const category = categorizeError(error, context); // Handle based on category if (category && ERROR_CATEGORIES[category]) { ERROR_CATEGORIES[category].handler(error); } else { // Default error handling defaultErrorHandler(error); } // Report error for monitoring reportError(error, { ...context, category }); }; // Function to categorize errors export const categorizeError = (error, context = {}) => { // Check for specific error codes if (error.code) { for (const [categoryName, category] of Object.entries(ERROR_CATEGORIES)) { if (category.codes.includes(error.code.toUpperCase())) { return categoryName; } } } // Check for HTTP status codes if (error.status || (error.response && error.response.status)) { const status = error.status || error.response.status; if (status >= 400 && status < 500) { if (status === 401 || status === 403) { return 'AUTHENTICATION'; } return 'VALIDATION'; } else if (status >= 500) { return 'SERVER'; } } // Check for network-related errors if (error.isAxiosError && !error.response) { return 'NETWORK'; } // Check for specific error messages const errorMessage = error.message || ''; if (errorMessage.toLowerCase().includes('network')) { return 'NETWORK'; } // Check for context clues if (context.operation === 'authentication') { return 'AUTHENTICATION'; } // Default to unknown category return null; }; // Default error handler const defaultErrorHandler = (error) => { const message = error.message || 'An unexpected error occurred.'; showErrorToast(message); }; // Enhanced API error handler with orchestration export const handleApiErrorWithOrchestration = (error, context = {}) => { // Add context about the API call const enrichedContext = { ...context, type: 'api_error', url: error.config?.url, method: error.config?.method, timestamp: new Date().toISOString() }; // Orchestrated error handling orchestrateError(error, enrichedContext); // Return a rejected promise with the error for further handling return Promise.reject(error); }; // Component error handler with orchestration export const handleComponentError = (error, context = {}) => { // Add context about the component const enrichedContext = { ...context, type: 'component_error', component: context.componentName || 'Unknown Component', timestamp: new Date().toISOString() }; // Orchestrated error handling orchestrateError(error, enrichedContext); }; ``` ### 6. Using Error Handling in Components Here's how to implement error handling in your components: ```jsx // pages/Dashboard.jsx import React, { useState, useEffect } from 'react'; import ErrorBoundary from '../components/ErrorBoundary'; import { ToastProvider, useToast } from '../components/ToastProvider'; import { useErrorHandler } from '../hooks/useErrorHandler'; import { orchestrateError } from '../utils/errorOrchestrator'; const DashboardContent = () => { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const { showError } = useToast(); const { handleError } = useErrorHandler(); useEffect(() => { fetchData(); }, []); const fetchData = async () => { try { setLoading(true); // Simulate API call const response = await fetch('/api/dashboard-data'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); setData(result); } catch (error) { // Use orchestrated error handling orchestrateError(error, { operation: 'fetch_dashboard_data', component: 'Dashboard' }); } finally { setLoading(false); } }; if (loading) { return
Loading dashboard...
; } return (

Dashboard

{data ? (

Welcome to your dashboard!

{JSON.stringify(data, null, 2)}
) : (

No data available

)}
); }; const Dashboard = () => { return ( ); }; export default Dashboard; ``` ### 7. API Route Error Handling For Next.js API routes, implement error handling as follows: ```javascript // pages/api/tasks/index.js import { handleApiError, handleApiErrorWithOrchestration } from '../../../utils/globalErrorHandler'; import { orchestrateError } from '../../../utils/errorOrchestrator'; export default async function handler(req, res) { try { switch (req.method) { case 'GET': // Handle GET request const tasks = await getTasks(); res.status(200).json({ tasks }); break; case 'POST': // Handle POST request const newTask = await createTask(req.body); res.status(201).json({ task: newTask }); break; default: res.setHeader('Allow', ['GET', 'POST']); res.status(405).end(`Method ${req.method} Not Allowed`); } } catch (error) { // Use orchestrated error handling for API routes await handleApiErrorWithOrchestration(error, { operation: 'api_handler', method: req.method, url: req.url, userId: req.userId // if available }); // The error has already been reported and handled by the orchestration // Just send a generic error response to the client res.status(500).json({ error: true, message: 'Internal server error' }); } } // Example helper functions async function getTasks() { // Implementation for getting tasks // This might throw errors that get caught by the try-catch throw new Error('Database connection failed'); } async function createTask(data) { // Implementation for creating a task // This might throw validation errors or other issues if (!data.title) { const error = new Error('Title is required'); error.code = 'VALIDATION_ERROR'; error.status = 400; throw error; } // Create the task... return { id: 1, title: data.title, status: 'pending' }; } ``` ## Additional Features The error handling system includes: - Comprehensive error boundary for component-level errors - Global error handlers for uncaught exceptions - Toast notifications for user feedback - Intelligent error categorization and handling - Centralized error reporting - Context-aware error handling - API-specific error handling utilities ## Security Considerations - Don't expose sensitive information in error messages to end users - Log detailed errors server-side but send generic messages to clients - Implement proper error sanitization before displaying to users - Use error reporting services to monitor and track errors in production - Implement rate limiting for error reports to prevent flooding - Sanitize error data before sending to external services