Handle errors safely with try-catch patterns for async code, error propagation, global handlers, and JSON parsing.
try blocks to intercept runtime errors.try-catch with await to catch rejected promises cleanly.window error event listeners.finally block when managing resources like file handles or database connections to guarantee cleanup.cause option in the Error constructor to preserve the original traceback when wrapping error exceptions.catch blocks that swallow errors silently, as this makes diagnosing application bugs very difficult.try-catch statement because it masks syntax errors during load time.try...catchCatches errors thrown during asynchronous operations when combined with await.
async function loadUser(id) {
try {
const res = await fetch(`/users/${id}`);
return await res.json();
} catch (err) {
console.error(err.message);
return null;
}
}Multiple awaitsGroups multiple sequential asynchronous actions into a single error handler block.
try {
const user = await getUser();
const orders = await getOrders(user.id);
console.log(orders);
} catch (err) {
console.error("Chain failed", err);
}finallyGuarantees resource cleanup or UI state resets regardless of try-catch outcomes.
setLoading(true);
try {
await saveData(form);
} catch (err) {
showError(err.message);
} finally {
setLoading(false);
}throwRethrows a caught error to escalate it up the application call stack.
function processData(raw) {
try {
return JSON.parse(raw);
} catch (err) {
console.warn("Parsing failed", err);
throw err;
}
}error causeAttaches a low-level error cause when throwing a new high-level wrapper error.
try {
await db.query(sql);
} catch (cause) {
throw new Error("DB failed", { cause });
}cause propertyRetrieves the nested origin error object from the cause property during inspection.
try {
await loadData();
} catch (err) {
console.log(err.cause.message);
}window.onerrorListens for unhandled synchronous execution errors globally across browser page environments.
window.onerror = (msg, src, line) => {
console.error(`Error: ${msg} at ${src}:${line}`);
return true; // intercept
};unhandledrejectionCatches any promise rejections that lack a corresponding catch block handler.
window.addEventListener("unhandledrejection", e => {
console.error("Unhandled:", e.reason);
e.preventDefault();
});uncaughtExceptionListens for terminal exceptions globally in Node.js process environments.
process.on("uncaughtException", err => {
console.error("Fatal error occurred:", err);
process.exit(1);
});JSON.parse()Safeguards JSON parsing routines by catching syntax validation failures.
function parseJSON(str, fallback = null) {
try {
return JSON.parse(str);
} catch {
return fallback;
}
}Optional catchOmits the catch block error variable binding when the object is unused.
try {
data = JSON.parse(raw);
} catch {
data = {};
}localStorage guardProtects localStorage reads which can throw errors in private browser modes.
function getStored(key) {
try {
return JSON.parse(localStorage.getItem(key));
} catch {
return null;
}
}error.stackProvides trace details including file locations and execution call history.
try {
riskyOperation();
} catch (err) {
console.error(err.stack);
}cause tracingRecursively traverses a wrapped error cause chain to resolve the root error.
try {
await saveOrder(order);
} catch (err) {
let current = err;
while (current?.cause) {
current = current.cause;
}
console.log("Root:", current.message);
}AggregateErrorCollects multiple individual promise errors during collective parallel operations.
try {
await Promise.any([checkA(), checkB()]);
} catch (err) {
err.errors.forEach(e => console.log(e.message));
}Use try-catch blocks for unpredictable operations like JSON.parse() or network requests. For values you can verify beforehand using variables or properties, choose conditional null checks instead. Conditional checks are faster and cleaner.
Inspect the caught exception using the instanceof operator inside the catch block. For example, check if (err instanceof TypeError) to handle specific issues. Always rethrow unknown exceptions with throw err to prevent swallowing bugs.
Yes, the finally block is guaranteed to execute even if the try block calls return. It runs right before the function exits. This makes it perfect for resetting loading states and releasing resource handles.
Extend the built-in Error class: class ValidationError extends Error { ... }. Set this.name inside the constructor method. Extending the class ensures you maintain the correct stack trace for debugging.
Yes, wrapping an await statement inside a try-catch block catches promise rejections. This synchronous-like syntax avoids trailing .catch() chains. It simplifies error handling across multiple sequential asynchronous requests.
Custom Network Error Wrapping
Wraps network and response parsing exceptions inside a custom error class to maintain context and track causes.
NetworkError constructor.try block.catch block handler.NetworkError wrapping the original error as the cause.class NetworkError extends Error {
constructor(msg, cause) {
super(msg, { cause });
this.name = "NetworkError";
}
}
async function fetchJson(url) {
try {
const res = await fetch(url);
if (!res.ok) throw new Error(res.statusText);
return await res.json();
} catch (err) {
throw new NetworkError("Fetch failed", err);
}
}Extend the standard Error class and utilize cause wrapping to propagate debuggable contextual exceptions safely.