JavaScript Error Handling
Errors happen in every program. Good code expects them and handles them, so the page does not break for the user.
What Happens Without Handling
When an error happens and nobody handles it, JavaScript stops running the rest of that script. Any code after the error line never runs.
Example
console.log("Start");
const user = null;
console.log(user.name); // TypeError: the script stops here
console.log("End"); // never runstry and catch
Put code that might fail inside try. If an error happens, JavaScript jumps straight to catch, and the program keeps going.
Example
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
const out = document.getElementById("demo");
try {
const user = null;
out.innerHTML = user.name;
} catch (error) {
out.innerHTML = "Something went wrong.<br>" +
"Type: " + error.name + "<br>" +
"Message: " + error.message;
}
out.innerHTML += "<br>The page still works!";
</script>
</body>
</html>Try it Yourself »Something went wrong. Type: TypeError Message: Cannot read properties of null (reading 'name') The page still works!
The error object always has:
name: the type of error, like"TypeError"message: a description of what went wrongstack: where in the code it happened (useful for debugging)
finally
Code in finally runs always: after try succeeds, and after catch handles an error. Use it for clean-up, like hiding a loading message.
Example
function divideBill(total, people) {
try {
if (people <= 0) throw new Error("Number of people must be at least 1");
return Math.round(total / people);
} catch (error) {
console.log("Error:", error.message);
return 0;
} finally {
console.log("Calculation finished");
}
}
console.log(divideBill(3000, 4));
console.log(divideBill(3000, 0));Calculation finished 750 Error: Number of people must be at least 1 Calculation finished 0
finally runs even when try or catch contains return.
Throwing Your Own Errors
Use throw to stop when something is wrong. Always throw an Error object (not a plain string), so you get a name, message and stack.
Example
function setAge(age) {
if (typeof age !== "number") {
throw new TypeError("Age must be a number");
}
if (age < 5 || age > 100) {
throw new RangeError("Age must be between 5 and 100");
}
return age;
}Built-in Error Types
| Type | Happens when |
|---|---|
SyntaxError | The code is written wrongly (also from JSON.parse with bad text) |
ReferenceError | You use a variable that does not exist |
TypeError | A value is the wrong type, like calling null.name or 5() |
RangeError | A number is outside the allowed range |
Error | The general type for your own errors |
Custom Error Classes
For bigger programs, create your own error types by extending Error. Then you can check which error happened with instanceof.
Example
<!DOCTYPE html>
<html>
<body>
<input id="amount" type="number" placeholder="Amount in Rs">
<button id="pay">Withdraw</button>
<p id="msg"></p>
<script>
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
class BalanceError extends Error {
constructor(needed) {
super("Not enough balance. You need Rs " + needed + " more.");
this.name = "BalanceError";
this.needed = needed;
}
}
let balance = 5000;
function withdraw(amount) {
if (!amount || amount <= 0) throw new ValidationError("Enter an amount above 0.");
if (amount > balance) throw new BalanceError(amount - balance);
balance -= amount;
return balance;
}
document.getElementById("pay").addEventListener("click", () => {
const msg = document.getElementById("msg");
try {
const left = withdraw(Number(document.getElementById("amount").value));
msg.textContent = "Done! Balance left: Rs " + left;
} catch (error) {
if (error instanceof ValidationError) {
msg.textContent = "Input problem: " + error.message;
} else if (error instanceof BalanceError) {
msg.textContent = error.message;
} else {
throw error; // unknown error: let it go up
}
}
});
</script>
</body>
</html>Try it Yourself »Try 0, 2000 and then 9000.
Only catch errors you know how to handle. If you catch an error and do nothing, a real bug becomes invisible. Re-throw anything you did not expect.
Error Cause
When you catch one error and throw a new, clearer one, pass the original as cause so no detail is lost:
Example
try {
JSON.parse("{bad json}");
} catch (err) {
const wrapped = new Error("Could not read saved settings", { cause: err });
console.log(wrapped.message, "|", wrapped.cause.name);
}Could not read saved settings | SyntaxError
Exercise
Exercise
When does the code inside a finally block run?
