In short
Networks fail, users type nonsense and APIs change without telling you. Good error handling means your app shows a helpful message instead of a blank white screen.
`try`/`catch`/`finally` and custom `Error` subclasses let you gracefully handle failures instead of letting them crash your app silently. Robust error handling should distinguish expected failures from programming bugs, preserve useful context, provide user-safe messages, and make failures observable during development.

Think of it like this
The hostel inverter
Power cuts happen. Without an inverter, everything goes dark. With one, the fans keep spinning and someone calls the electrician. try is normal power, catch is the inverter kicking in, and finally is switching off the main once it's over, cut or no cut.
Watch it happen
What happens when parseAge throws
Top of the stack is coloured
1/10Code enters the try block.
The big ideas
What you need to know
try, catch, finally
Risky code goes in try. If it throws, catch gets the error. finally runs either way, good for cleanup.
Throw Error objects
throw new Error("message") gives you a message and a stack trace. Throwing plain strings loses the stack.
Custom error types
Extend Error to make ValidationError or NetworkError, then check with instanceof to handle each one differently.
Async needs await
try/catch only catches a promise's error if you await it inside the try block.
See it in code
Walk through the code
1class ValidationError extends Error {2 constructor(message) { super(message); this.name = "ValidationError"; }3}4function parseAge(text) {5 const age = Number(text);6 if (Number.isNaN(age)) throw new ValidationError("Age must be a number");7 return age;8}9try {10 parseAge("twenty");11} catch (err) {12 if (err instanceof ValidationError) console.log(err.message); // "Age must be a number"13 else throw err; // not ours, let it go up14} finally {15 console.log("Done checking");16}1/5A custom error type with its own name.
Only handle errors you understand. Anything else gets thrown again so it isn't silently hidden.
Save yourself the pain
Common mistakes
Oops
Writing an empty catch {} to make the red error go away.
Do this instead
That hides real bugs. At least log the error, and show the user something useful.
Oops
Wrapping fetch(url) in try/catch without await.
Do this instead
The try ends before the promise fails. Write await fetch(url) inside try, or add .catch to the promise.
Your mission
Make a form fail nicely
Quick check
What happens? try { setTimeout(() => { throw new Error("x"); }, 0); } catch { console.log("caught"); }
Go deeper
- 1Wrap a risky operation (JSON parsing, a fetch call) in `try`/`catch`. Validate your understanding by applying it in a small practical example.
- 2Create a custom error class extending `Error` with extra context. Validate your understanding by applying it in a small practical example.
- 3Learn how errors propagate through `async` functions and Promise chains.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.