By the end, you can create, catch, and inspect JavaScript Error objects, choose built-in error types, and use their properties to handle failures clearly.
What it is
An Error object is JavaScript's structured way to describe something that went wrong. Think of it as a report card for a failure: it has a short message, a type name, an optional cause, and usually a stack trace showing where it was created.
Built-in error types include Error, TypeError, ReferenceError, RangeError, SyntaxError, URIError, and AggregateError. EvalError also exists but is rarely thrown in modern code. Related terms are throw, try, catch, instanceof, and cause.
Why it matters
- It gives failures a consistent shape instead of random strings or objects.
- It lets code branch on error type with
instanceofore.name. - It preserves debugging context through
stack. - It supports error chaining with
causein modern JavaScript. - It works with logging tools, test frameworks, and browser consoles.
Syntax or steps
The smallest useful pattern is to throw an Error, catch it, and inspect its properties.
try {
throw new Error("Something went wrong");
} catch (e) {
console.error(e.name, e.message);
}
Key properties:
message: human-readable description.name: error type, such as"TypeError".stack: debugging trace; widely available but not fully standardized.cause: optional underlying error or value.
Example
function parseAge(value) {
if (typeof value !== "number") {
throw new TypeError("Age must be a number");
}
if (value < 0 || value > 150) {
throw new RangeError("Age must be between 0 and 150");
}
return value;
}
try {
parseAge("30");
} catch (e) {
console.error(e.name + ": " + e.message);
if (e instanceof TypeError) {
console.error("Fix the input type.");
} else if (e instanceof RangeError) {
console.error("Fix the input range.");
}
}
Part by part: parseAge checks the input. If the type is wrong, it throws a TypeError. If the number is outside the allowed range, it throws a RangeError. The catch block receives the thrown object as e. It logs e.name and e.message, then uses instanceof to decide what kind of problem occurred.
Common mistakes
- Throwing a string, such as
throw "bad input". Fix: throw anErrorso it hasname,message, andstack. - Using
stackfor program logic. Fix: usemessage,name, orinstanceof; keepstackfor debugging. - Catching errors and doing nothing. Fix: log, recover, or rethrow with context:
throw new Error("Failed to load user", { cause: e }). - Choosing the wrong built-in type. Fix: use
TypeErrorfor invalid types,RangeErrorfor invalid values,ReferenceErrorfor undeclared identifiers, andSyntaxErrorfor invalid syntax.
When to use it
Use an Error object when a failure should be handled as a failure. Compare it with throwing a plain object or string.
| Approach | Best for | Watch out |
|---|---|---|
Built-in Error types | Common runtime failures | Do not rely on exact stack text |
Custom subclass of Error | Domain-specific failures, such as ValidationError | Set this.name so logs are clear |
| Plain object | Structured data that is not really an exception | No standard error behavior |
| String | Quick experiments only | Loses type, stack, and chaining |
Practice
Guided exercise: write a function called divide that throws a TypeError if either argument is not a number, and throws an Error if the divisor is zero.
function divide(a, b) {
if (typeof a !== "number" || typeof b !== "number") {
throw new TypeError("Both arguments must be numbers");
}
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
try {
divide(10, "2");
} catch (e) {
console.error(e.name + ": " + e.message);
}
Expected output: TypeError: Both arguments must be numbers.
Challenge: create a custom ValidationError class that extends Error and stores the invalid field in a property called field.
Solution hint: define class ValidationError extends Error, call super(message), set this.name = "ValidationError", and assign this.field = field.
Quick check
Question: Which property tells you the built-in type of an error, such as TypeError or RangeError?
Answer: The name property.
Summary
The Error object turns failures into inspectable values with a message, type, stack, and optional cause. Built-in types let you describe common problems precisely, while custom subclasses let you model domain-specific failures. Prefer throwing Error objects over strings or plain objects when you want consistent, debuggable error handling.