DEV Community

Cover image for JavaScript Error Handling Patterns You Must Know (With Examples & Best Practices)
ROHIT SINGH
ROHIT SINGH

Posted on

JavaScript Error Handling Patterns You Must Know (With Examples & Best Practices)

Errors are an unavoidable part of software development. Whether it’s a typo, a failed API call, or unexpected user input, JavaScript errors can break your application if not handled properly.
Good error handling ensures your app is reliable, debuggable, and user-friendly.

In this blog, we’ll explore essential error handling patterns in JavaScript, complete with examples and best practices.

🔹 1. The Classic try...catch

The most common way to handle errors in JavaScript is using try...catch.

function parseJSON(data) { try { return JSON.parse(data); } catch (error) { console.error("Invalid JSON:", error.message); return null; } } console.log(parseJSON('{ "name": "Anshul" }')); // ✅ Works console.log(parseJSON("invalid-json")); // ❌ Error handled gracefully 
Enter fullscreen mode Exit fullscreen mode

👉 Best Practice:

Always provide a fallback when something goes wrong.

Log errors with context, not just a generic message.

🔹 2. Using finally

finally is executed regardless of success or failure, useful for cleanup.

function fetchData() { try { console.log("Fetching data..."); throw new Error("Network issue!"); } catch (error) { console.error("Error:", error.message); } finally { console.log("Cleanup resources, close connections, etc."); } } fetchData(); 
Enter fullscreen mode Exit fullscreen mode

👉 Best Practice:
Use finally to release resources like file handles, database connections, or loading states.

🔹 3. Error Handling in Async/Await

When using async/await, wrap code in try...catch.

async function getUser() { try { const res = await fetch("https://api.example.com/user"); const data = await res.json(); console.log(data); } catch (error) { console.error("Failed to fetch user:", error.message); } } getUser(); 
Enter fullscreen mode Exit fullscreen mode

👉 Best Practice:
Always assume network calls can fail. Show user-friendly error messages instead of crashing.

🔹 4. Centralized Error Handling

Instead of scattering try...catch everywhere, use a central handler.

function handleError(error) { console.error("Global Error Handler:", error.message); // Send error to monitoring service like Sentry } async function safeExecute(fn) { try { await fn(); } catch (error) { handleError(error); } } // Usage safeExecute(async () => { throw new Error("Something broke!"); }); 
Enter fullscreen mode Exit fullscreen mode

👉 Best Practice:
Centralized handlers make debugging easier and integrate well with logging/monitoring tools.

🔹 5. Graceful Degradation with Default Values

Sometimes, instead of crashing, fallback to a default value.

function getUserName(user) { try { return user.profile.name; } catch { return "Guest"; // fallback } } console.log(getUserName({ profile: { name: "Anshul" } })); // "Anshul" console.log(getUserName(null)); // "Guest" 
Enter fullscreen mode Exit fullscreen mode

👉 Best Practice:
Use fallbacks for non-critical failures (e.g., missing optional fields).
For critical failures, log them properly.

🔹 6. Error Boundaries in Frontend Apps

In React, Angular, Vue, use error boundaries to prevent full app crashes.

Example in React:

class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError() { return { hasError: true }; } componentDidCatch(error, info) { console.error("Error caught:", error, info); } render() { if (this.state.hasError) { return <h2>Something went wrong!</h2>; } return this.props.children; } } 
Enter fullscreen mode Exit fullscreen mode

👉 Best Practice:
Use error boundaries in UI frameworks to catch render-time crashes.

🔹 7. Custom Error Classes

Create custom error types for better debugging.

class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } } function validateAge(age) { if (age < 18) { throw new ValidationError("Age must be 18+"); } return true; } try { validateAge(16); } catch (error) { if (error instanceof ValidationError) { console.error("Validation failed:", error.message); } else { throw error; } } 
Enter fullscreen mode Exit fullscreen mode

👉 Best Practice:
Use custom errors for business logic checks (e.g., validation, permissions).

✅ Final Best Practices for Error Handling in JavaScript

🔸 Don’t swallow errors silently – always log them.

🔸 Use meaningful error messages with context.

🔸 Centralize error handling for maintainability.

🔸 Use custom error classes for better debugging.

🔸 Integrate with monitoring tools (Sentry, LogRocket, etc.).

🔸 Show user-friendly messages, not stack traces.

🚀 Conclusion

Error handling is not just about preventing crashes—it’s about building resilient, debuggable, and user-friendly applications.
By applying these patterns and best practices, you’ll write cleaner, safer JavaScript code that handles the unexpected gracefully.

🚀 Rohit Singh 🚀 – Medium

Read writing from 🚀 Rohit Singh 🚀 on Medium. Full-stack developer with 6+ years in Angular, Node.js & AWS. Sharing tips, best practices & real-world lessons from building scalable apps.

favicon medium.com

Top comments (0)