⚡IntermediateAsync JavaScript
Error Handling
Catch and recover from runtime errors using try/catch/finally, custom Error classes, and async error patterns.
Overview
Errors are inevitable in any program invalid input, network failures, unexpected null values, logic bugs. JavaScript provides try/catch/finally as the primary mechanism for handling runtime errors gracefully instead of crashing.
The try block contains code that might throw. If anything inside it throws, execution jumps immediately to the catch block, which receives the Error object. The finally block (optional) runs regardless of whether an error was thrown it is the right place for cleanup code like closing connections or hiding spinners.
Beyond the built-in Error types (TypeError, RangeError, SyntaxError), you can define custom Error subclasses to represent domain-specific failure conditions making it easy to distinguish "user not found" from "network timeout" in a catch block. Understanding error handling in both synchronous and asynchronous code is essential for writing robust JavaScript.
Key Points
- •try/catch/finally is the core error handling construct catch receives the thrown value
- •The throw statement can throw anything, but throwing Error objects is the convention
- •Built-in error types: Error, TypeError, RangeError, SyntaxError, ReferenceError
- •Extend Error with class MyError extends Error to create domain-specific error types
- •In async code: .catch() handles Promise rejections; try/catch works inside async functions
- •finally always runs even if try returns early making it ideal for cleanup
- •err.message is the human-readable description; err.name is the error type; err.stack has the trace
- •Re-throwing: catch an error, inspect it, and throw it again if you cannot handle it
Examples
try/catch/finally basics
function parseJSON(str) {
try {
const result = JSON.parse(str);
return result;
} catch (err) {
console.error("Parse failed:", err.message);
return null;
} finally {
console.log("parseJSON finished"); // always runs
}
}
console.log(parseJSON('{"name":"Alice"}')); // { name: "Alice" }
console.log(parseJSON("not valid json")); // Parse failed: ..., then nullCustom Error classes
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}
class NotFoundError extends Error {
constructor(resource, id) {
super(`${resource} with id ${id} not found`);
this.name = "NotFoundError";
this.statusCode = 404;
}
}
function getUser(id) {
if (typeof id !== "number") throw new ValidationError("id", "id must be a number");
if (id !== 1) throw new NotFoundError("User", id);
return { id: 1, name: "Alice" };
}
try {
getUser(99);
} catch (err) {
if (err instanceof NotFoundError) {
console.log(`404: ${err.message}`);
} else if (err instanceof ValidationError) {
console.log(`Invalid ${err.field}: ${err.message}`);
} else {
throw err; // re-throw unexpected errors
}
}Error handling in async/await code
async function loadData(url) {
let response;
try {
response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (err) {
if (err instanceof TypeError) {
// fetch throws TypeError for network failures
console.error("Network error:", err.message);
} else {
console.error("Request failed:", err.message);
}
return null;
}
}
loadData("https://jsonplaceholder.typicode.com/posts/1")
.then(data => data && console.log("Title:", data.title));fetch() only rejects on network failure (TypeError). HTTP errors like 404 resolve successfully you must check response.ok.
Common Mistakes
- Catching errors and silently swallowing them always at minimum log the error or re-throw it
- Not setting this.name in custom Error subclasses without it, err.name shows "Error" not your custom type
- Using catch (err) {} with an empty body hides bugs that would otherwise surface early
- Forgetting that fetch does not reject on 4xx/5xx HTTP responses always check response.ok
Note
When you catch an error but cannot handle it meaningfully, re-throw it: catch (err) { log(err); throw err; }. This lets errors bubble to a level that can actually deal with them, while still logging where they originated.
Exercises
Write JavaScript code to solve each exercise. Run it and check your output.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4