Errors will happen, every time you write code. Some are typing mistakes, some come from bad input, and some from things you never expected. This lesson introduces the kinds of errors JavaScript reports, how to read an error message, and a first look at try...catch, the tool for handling errors instead of crashing.
When JavaScript hits an error it cannot handle, it throws the error, stops, and reports it in the console. Nothing after that line runs:
console.log("Before");
console.log(price * 2); // price was never declared
console.log("After");
"After" never prints. In the browser console the error shows in red as Uncaught ReferenceError: price is not defined. "Uncaught" means nothing handled it.
Every error message has the same parts. Learn to read all of them before you start changing code:
| Part | Example | Tells you |
|---|---|---|
| Type | ReferenceError | What kind of problem it is |
| Message | price is not defined | The specific problem, often naming the culprit |
| Location | script.js:2 | The file and line number (click it in the console to jump there) |
Put code that might fail in a try block. If an error is thrown, JavaScript jumps to the catch block instead of stopping, and hands you the error object (here named err). The two always come as a pair:
let x = 5;
try {
x = y + 1; // y does not exist
} catch (err) {
console.log(err.name);
console.log(err.message);
}
console.log("The program keeps going");
Every error object has a name (its type) and a message. JS Error Statements covers try, catch, finally, and throw in full; the rest of this lesson uses try...catch only to show you each type of error.
A ReferenceError means you used a name that does not exist (usually a typo or a missing let/const), or used a let/const variable before its line (the temporal dead zone from JS Hoisting):
try {
let fname = foo;
} catch (err) {
console.log(err.name + ": " + err.message);
}
try {
let x = y;
let y = 5;
} catch (err) {
console.log(err.name + ": " + err.message);
}
A TypeError means the value exists, but you used it in a way its type does not allow: calling something that is not a function, using a string method on a number, reading a property of undefined or null, or changing a const:
const tests = [
() => { let anna = 5; anna(5); },
() => { let num = 1; num.toUpperCase(); },
() => { let user; user.name; },
() => { const total = 1; total = 2; }
];
for (const test of tests) {
try {
test();
} catch (err) {
console.log(err.name + ": " + err.message);
}
}
The third one is the most common error in all of JavaScript. JS Debugging shows how to track down which value was undefined.
A RangeError means a number is outside the range a method accepts:
const tests = [
() => new Array(-1),
() => (1).toPrecision(500),
() => "abc".repeat(-1),
() => { function forever() { return forever(); } forever(); }
];
for (const test of tests) {
try {
test();
} catch (err) {
console.log(err.name + ": " + err.message);
}
}
The last one comes from a function that calls itself forever. Each call waits for the next, until JavaScript runs out of room to keep track of them.
A URI (Uniform Resource Identifier) is a web address. encodeURIComponent makes text safe to put in a URL, and decodeURIComponent / decodeURI turn it back. A URIError means the text to decode is broken:
console.log(encodeURIComponent("Tom & Jerry"));
console.log(decodeURIComponent("Tom%20%26%20Jerry"));
try {
decodeURI("%%%"); // % must be followed by two hex digits
} catch (err) {
console.log(err.name + ": " + err.message);
}
A SyntaxError means the code breaks JavaScript's grammar rules. These are different from all the others: JavaScript reads (parses) the whole script before running any of it, so a syntax error anywhere means none of that script runs, not even the lines above it.
| Code | Chrome says | Problem |
|---|---|---|
| let fName = "John); | Invalid or unexpected token | The string is never closed |
| Math.round(4.6; | missing ) after argument list | A ( with no matching ) |
| if (x == 5 { | Unexpected token '{' | The ) is missing before { |
| if (ok) { | Unexpected end of input | A { with no matching } |
| let 1st = "a"; | Invalid or unexpected token | Names cannot start with a digit |
Because the script never starts, a try...catch in the same script cannot catch its own syntax error. But text that is parsed while the program runs, like JSON, throws a SyntaxError you can catch:
try {
JSON.parse("{bad json}");
} catch (err) {
console.log(err.name);
console.log(err instanceof SyntaxError);
}
Invalid or unexpected token (no parenthesis) and missing ) after argument list (lowercase).err.description. description is a non-standard property that only old Microsoft browsers had (see JS Error Object).EvalError as a type to know. It is a leftover: modern JavaScript does not throw it for eval() problems, so you will almost never see one.Some mistakes do not throw anything. 1 / 0 quietly gives Infinity and "abc" * 5 gives NaN, and the program keeps running with wrong data. Those are the subject of the next lesson, JS Silent Errors.
| Error | Means | Common cause |
|---|---|---|
| ReferenceError | That name does not exist (yet) | Typo, missing let/const, used before declared |
| TypeError | Wrong kind of value for that operation | undefined/null property, not a function, const reassigned |
| RangeError | A number out of the allowed range | Bad length or digit count, endless recursion |
| URIError | Broken URL encoding | A stray % when decoding |
| SyntaxError | Code (or JSON) breaks grammar rules | Missing ) } or quote, bad JSON |
What does this log?
try {
null.length;
} catch (e) {
console.log(e.name);
}
TypeError. null has no properties, so reading .length is using a value in a way its type does not allow.Which error does let 1st = "a"; cause?
SyntaxError: Invalid or unexpected token.A script starts with console.log("Before"); and has a syntax error on line 20. Why does "Before" never print?
ReferenceError, a TypeError, and a RangeError on purpose, and catch each oneerr.name and err.message for each error you caught) and read the SyntaxError in the Consoletry...catch around JSON.parse to handle bad JSON without crashing