Back to Tutorials
🛡️ Intermediate

Error Handling

7 min read | Error Handling

Error Handling

Proper error handling makes your code robust and debuggable.

Try-Catch-Finally

try {
  // Code that might throw an error
  const data = JSON.parse(invalidJson);
} catch (error) {
  // Handle the error
  console.error('Parse error:', error.message);
} finally {
  // Always runs
  console.log('Cleanup complete');
}

Throwing Errors

function divide(a, b) {
  if (b === 0) {
    throw new Error('Division by zero');
  }
  return a / b;
}

// Custom error types class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; } }

throw new ValidationError('Email is invalid');

Error Types

// Built-in error types
new Error('Generic error');
new TypeError('Type mismatch');
new ReferenceError('Variable not found');
new SyntaxError('Invalid syntax');
new RangeError('Value out of range');

// Checking error type try { // ... } catch (error) { if (error instanceof TypeError) { console.log('Type error occurred'); } else if (error instanceof ReferenceError) { console.log('Reference error occurred'); } }

Async Error Handling

// With promises
fetchData()
  .then(data => process(data))
  .catch(error => console.error(error));

// With async/await async function getData() { try { const data = await fetchData(); return data; } catch (error) { console.error('Failed to fetch:', error); throw error; // Re-throw if needed } }

Best Practices

// 1. Be specific about what you catch
try {
  // Specific operation
} catch (error) {
  if (error.code === 'NETWORK_ERROR') {
    // Handle network error
  } else {
    throw error; // Re-throw unexpected errors
  }
}

// 2. Log errors with context function processUser(userId) { try { // Process } catch (error) { console.error(Error processing user ${userId}:, error); throw error; } }

// 3. Use error boundaries in React class ErrorBoundary extends React.Component { componentDidCatch(error, info) { logError(error, info); } }