Introduction
Things go wrong in every real program: a user types nonsense, a file is missing, a server is down. A good program plans for these. Error handling is what lets it say "that date is not valid" and carry on, instead of stopping with a white screen. Reading error messages calmly is also one of the most useful skills a developer can have.
How it works
When something goes wrong, JavaScript throws an error object. If nothing catches it, the program stops and the message says what happened and on which line:
| Error | Usually means | Example |
|---|---|---|
SyntaxError | the code is not valid JavaScript | a missing bracket |
ReferenceError | a name that does not exist (yet) | a typo in a variable name |
TypeError | the wrong kind of value | calling undefined() or reading a property of null |
RangeError | a number out of its allowed range | new Array(-1), endless recursion |
// An error nobody catches stops the program.
const user = { name: "Rahim", address: null };
console.log("Name:", user.name);
console.log("City:", user.address.city); // address is null
console.log("This line never runs");The visualizer stops at the line that threw and explains the error.
Catching errors. Code that may fail goes in a try block. If anything in it throws, JavaScript jumps straight to catch, which gets the error object. finally runs at the end either way, which suits clean-up work.
Throwing your own. throw new Error("message") stops the current function and hands the error to the nearest catch up the call stack. A class that extends Error gives your errors their own name, so a catch can tell them apart with instanceof:
// Your own error class, thrown and caught.
class InsufficientFunds extends Error {
constructor(needed) {
super(`Not enough money: need ${needed} more`);
this.name = "InsufficientFunds";
}
}
function withdraw(balance, amount) {
if (amount > balance) {
throw new InsufficientFunds(amount - balance);
}
return balance - amount;
}
for (const amount of [300, 900]) {
try {
console.log("Left:", withdraw(500, amount));
} catch (err) {
if (err instanceof InsufficientFunds) {
console.log(err.message);
} else {
throw err;
}
}
}Notice how the function that finds the problem and the code that decides what to do about it can be far apart. That is the main advantage of throwing an error over returning a special value.
Syntax
try {
riskyWork();
} catch (err) {
console.log(err.name, err.message);
} finally {
cleanUp();
}
throw new Error("Something is wrong");
Example
// try, catch and finally around JSON.parse.
function readAge(text) {
try {
const data = JSON.parse(text);
return data.age;
} catch {
// No (err) here: this catch does not need the error object.
console.log("Bad JSON, so the age is unknown");
return null;
} finally {
console.log("Checked", text);
}
}
console.log(readAge('{"age": 21}'));
console.log(readAge("{age: 21}"));Line by line
readAgeputs the riskyJSON.parseinsidetry.- With valid JSON, it returns
data.age. Before the function actually leaves,finallyprints its line. - So the first call prints
Checked ...before the21is printed by the outerconsole.log. - The second text has no quotes around its key, so
JSON.parsethrows. catchprints its message and returnsnull, andfinallystill runs.
Expected result
Checked {"age": 21}
21
Bad JSON, so the age is unknown
Checked {age: 21}
null
In the real world
Every network request can fail, so a good app shows "Could not load, please try again" instead of breaking. Servers catch errors for each request, so that one bad request cannot bring down the service for everybody else.
Common mistakes
- An empty
catchthat hides every error. At least print it. - Wrapping a whole program in one try. Catch errors where you can do something useful about them.
- Throwing a string, as in
throw "bad". Throw an Error object, which records the message and where it happened. - Expecting
tryto catch a SyntaxError in the same script. A script with a syntax error never starts.
Best practices
- Check input early, and throw a clear message when it is wrong.
- Re-throw any error your
catchdoes not know how to handle. - Write messages that say what went wrong and what was expected.
- Read the error's name, its message and its line number before you change any code.
Summary
Errors are objects that are thrown and travel up the call stack until something catches them. try and catch handle them, and finally always runs. Your own error classes let a catch block respond differently to different problems.
Quick check
Key takeaways
- An uncaught error stops the program.
- Catch an error only where you can do something useful about it.
- Throw Error objects, not strings.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.