Intermediate · Modules, errors, JSON and dates · topic 27 of 61 · 30 min
Error handling: try, catch, finally and throw
Explanation
What is an error?
An error (also called an exception) is an object that describes a problem. When code throws one, the current function stops immediately and the error travels up the call stack until some code catches it. If nothing catches it, the program crashes (in Node) or the console shows "Uncaught …" (in the browser).
const user = null;
console.log(user.name);
// TypeError: Cannot read properties of null (reading 'name')Built-in error types
| Type | Typical cause |
|---|---|
| TypeError | Using a value the wrong way: calling undefined, reading a property of null |
| ReferenceError | Using a variable that does not exist, or a let/const in its TDZ |
| RangeError | A number out of range: new Array(-1), too much recursion, toFixed(200) |
| SyntaxError | Code (or JSON.parse input) that is not valid |
| Error | The general type you usually throw yourself |
Every error has a name ('TypeError'), a message (the human text) and usually a stack (the list of function calls that led to it, with file names and line numbers). Read the first line of the stack that points to YOUR code.
try, catch and finally
function parseAmount(text) {
try {
const n = JSON.parse(text); // may throw SyntaxError
console.log('parsed');
return n;
} catch (error) {
console.log('Could not parse:', error.message);
return 0;
} finally {
console.log('done'); // runs in every case
}
}
parseAmount('42'); // parsed, done
parseAmount('4 2'); // Could not parse: …, doneOrder: the try block runs; if it throws, the rest of try is skipped and catch runs; finally runs at the end whether there was an error or not, even after a return. Use finally for clean-up: closing a file, hiding a loading spinner.
Throwing your own errors
function withdraw(balance, amount) {
if (typeof amount !== 'number' || amount <= 0) {
throw new RangeError(`Invalid amount: ${amount}`);
}
if (amount > balance) throw new Error('Insufficient balance');
return balance - amount;
}Custom error classes and cause
class NotFoundError extends Error {
constructor(what) {
super(`${what} not found`);
this.name = 'NotFoundError';
}
}
try {
try {
throw new NotFoundError('PNR 4521');
} catch (inner) {
throw new Error('Booking lookup failed', { cause: inner }); // wrap with cause
}
} catch (e) {
console.log(e.message, '←', e.cause.message);
// Booking lookup failed ← PNR 4521 not found
}With a custom class you can react to specific problems with instanceof: if (e instanceof NotFoundError) show a 404 page, otherwise re-throw.
Where to handle errors
- Validate input at the boundaries (forms, API requests, file reads) and throw clear errors early.
- Catch errors where you can do something useful: show a message, retry, use a default.
- Let unexpected errors bubble up to one top-level handler that logs them.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Error handling: try, catch, finally and throw · 1/6
In this lesson you will handle errors on purpose instead of letting the program crash.
Prefer a video by a teacher? Find free videos on “javascript error handling try catch finally throw custom errors” on YouTube ↗
In real life: Reading a bank statement file
A finance app imports a CSV bank statement. Some rows are broken. Instead of crashing on the first bad row, the importer catches the error for that row, records the line number and reason, and continues. At the end it shows "142 rows imported, 3 rows skipped" with the reasons.
const rows = ['2026-01-02,1500', 'bad row', '2026-01-05,-200'];
const ok = [], skipped = [];
rows.forEach((row, i) => {
try {
const [date, amount] = row.split(',');
if (!amount) throw new Error('missing amount');
ok.push({ date, amount: Number(amount) });
} catch (e) {
skipped.push(`line ${i + 1}: ${e.message}`);
}
});
console.log(ok.length, skipped); // 2 ['line 2: missing amount']Practice (0/3 done)
Write safeParse(text) that returns the parsed JSON value, or null if the text is not valid JSON. Use try/catch.
Write withdraw(balance, amount) that throws a RangeError with the message "Invalid amount" when amount is not a positive number, throws an Error with the message "Insufficient balance" when amount > balance, and otherwise returns the new balance.
Write runSteps(steps) where steps is an array of functions. Call each one in order inside try/catch. Return an object { done, failed } where done counts the steps that worked and failed is an array of the error messages. Always set a variable cleanedUp = true in finally.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- JSON: data in and outModules, errors, JSON and dates · same module
- Dates and timesModules, errors, JSON and dates · same module
- Exceptions: try, catch, finally and custom exceptionsC# and .NET · Exceptions, delegates, events and async
- Exceptions: try, catch and finallyJava Programming (Core to Spring Boot) · Exceptions and generics
- Errors and exceptionsPython Programming · Errors, modules and the standard library
- async/await and error handlingFrontend Web Development · Async JavaScript, modules and tools
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
When does finally run?
Answer: Always, after try (and catch)
finally runs in every case, even after return.
null.length throws which error?
Answer: TypeError
Reading a property of null is a TypeError.
Why throw new Error("…") instead of throw "…"?
Answer: Error objects carry a name and a stack trace
Strings can be thrown but have no stack, which makes debugging hard.
What is wrong with catch (e) {} ?
Answer: It hides the error so bugs go unnoticed
An empty catch swallows the problem silently.
When does a finally block run?Related
Answer: Always, whether or not an exception happened
finally is for guaranteed cleanup.
When does finally run?Related
Answer: Always, even after return
finally always runs (except if the JVM exits).
Where in a traceback do you find the error type and message?Related
Answer: On the last line
The last line names the error and gives the message. The lines above show where it happened.
Which problem reaches your catch block even if you never check response.ok?Related
Answer: The phone has no internet connection
A network failure makes fetch reject. HTTP errors still give a response, so you must check ok and throw yourself.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Modules, errors, JSON and dates” before its exam: JSON: data in and out, Dates and times, Formatting numbers, money and text with Intl.
- Module 6 exam: Modules, errors, JSON and dates · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Map, Set, iterators, generators and regular expressions. 61 topics left in the course before the final exam.