Throwing Errors
Sometimes your code should stop because something invalid happened.
In JavaScript, you can create that failure with throw.
throw new Error("Something went wrong");Throwing an error interrupts normal execution.
JavaScript looks for the nearest matching catch block.
Basic Example
function divide(a, b) {
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
try {
console.log(divide(10, 0));
} catch (error) {
console.log(error.message); // Cannot divide by zero
}The function refuses to return an invalid result.
The throw Statement
Syntax:
throw expression;You can technically throw any value:
throw "Failed";
throw 123;
throw { message: "Failed" };But best practice is to throw Error objects.
throw new Error("Failed");Error objects include useful debugging information such as:
namemessagestack
Why Throw Errors?
Throw errors when a function cannot do its job correctly.
Example:
function createUser(name) {
if (!name) {
throw new Error("Name is required");
}
return {
name,
active: true,
};
}Returning a fake user with invalid data would hide the problem.
Throwing makes the failure clear.
Validation Example
function setAge(age) {
if (!Number.isInteger(age)) {
throw new Error("Age must be an integer");
}
if (age < 0) {
throw new Error("Age cannot be negative");
}
return age;
}This protects the function's assumptions.
The rest of the program can trust that returned ages are valid.
Throwing Stops Execution
function example() {
console.log("Before");
throw new Error("Failed");
console.log("After");
}
try {
example();
} catch (error) {
console.log("Caught");
}Output:
Before
Caught"After" never runs.
Rethrowing Errors
Sometimes a function catches an error but cannot fully handle it.
It can rethrow the error.
function parseConfig(json) {
try {
return JSON.parse(json);
} catch (error) {
console.log("Config parsing failed");
throw error;
}
}The caller can catch it later.
You can also wrap it with more context.
function parseConfig(json) {
try {
return JSON.parse(json);
} catch (error) {
throw new Error(`Invalid config: ${error.message}`);
}
}Throwing in Constructors
Constructors can throw when invalid instances should not exist.
class Product {
constructor(name, price) {
if (price < 0) {
throw new Error("Price cannot be negative");
}
this.name = name;
this.price = price;
}
}This prevents creating invalid products.
Throwing vs Returning null
Sometimes a function can return null for a normal "not found" result.
function findUser(users, id) {
return users.find((user) => user.id === id) ?? null;
}This is not necessarily an error.
But invalid input may deserve an error.
function findUser(users, id) {
if (!Array.isArray(users)) {
throw new Error("users must be an array");
}
return users.find((user) => user.id === id) ?? null;
}Use judgment.
Not every absence is an exception.
Best Practices
Throw Error objects, not strings.
Use clear error messages.
Throw when a function cannot complete its responsibility.
Do not use errors for normal control flow.
Validate inputs at important boundaries.
Rethrow errors when the current function cannot handle them.
Common Mistakes
Mistake 1: Throwing Strings
throw "Invalid user";Prefer:
throw new Error("Invalid user");Mistake 2: Catching Errors Too Early
If a low-level function cannot recover, it may be better to let the caller handle the error.
Mistake 3: Using Errors for Expected Results
function findUser(users, id) {
const user = users.find((user) => user.id === id);
if (!user) {
throw new Error("User not found");
}
}If "not found" is a normal possibility, returning null may be clearer.
Quick Check
What does this log?
function test() {
throw new Error("Failed");
return "Done";
}
try {
console.log(test());
} catch (error) {
console.log(error.message);
}It logs:
FailedThe return after throw never runs.
Summary
throw creates an error and stops normal execution.
- Throw
Errorobjects with useful messages. - Throw when a function cannot complete correctly.
- Throwing skips the rest of the current execution path.
- A nearby
catchblock can handle the error. - Rethrow when the current code cannot fully handle the error.
- Do not use errors for normal expected outcomes.