JavaScript Error Types: Error, TypeError, and RangeError
JavaScript uses built-in error types to describe what went wrong when code fails at runtime or when you intentionally signal a problem. Understanding Error, TypeError, and RangeError helps you read stack traces faster, choose better exceptions, and write code that fails in a useful way.
Quick answer: Use Error for general failures, TypeError when a value has the wrong type or shape for an operation, and RangeError when a value is the right type but outside the allowed range.
Difficulty: Beginner
You'll understand this better if you know: basic JavaScript variables, functions, and how to read a simple stack trace.
1. What Is JavaScript Error?
JavaScript error types are standard objects that represent failures. They all describe problems, but each one points to a different kind of issue.
- Error is the general base type for failures.
- TypeError means the value cannot be used the way the code expects.
- RangeError means the value is valid in type, but not valid in amount, size, or position.
When code throws one of these errors, JavaScript stops the current flow unless you catch it with try...catch.
2. Why JavaScript Error Types Matter
These error types make debugging and API design much clearer. If you throw the right error, other developers can understand what went wrong without digging through implementation details.
They also help you write better validation. For example, if a function expects a number between 1 and 12, using RangeError tells the caller that the type may be correct, but the value is not allowed.
In real projects, these distinctions matter when you:
- validate function arguments
- report bad input from users or external APIs
- debug runtime failures from DOM, arrays, or objects
- build libraries that other developers will consume
3. Basic Syntax or Core Idea
All three error types are created with new. You can throw them directly or catch them after they are thrown.
Creating and throwing an error
The simplest pattern is to create an error instance with a message, then throw it.
throw new Error("Something went wrong");This creates an exception object and stops normal execution until the error is handled.
Catching an error
You can catch the thrown error and inspect its name and message.
try {
throw new TypeError("Expected a function");
} catch (error) {
console.log(error.name); // TypeError
console.log(error.message); // Expected a function
}The name property identifies the error class, while message explains the failure in human-readable form.
4. Step-by-Step Examples
Example 1: General failure with Error
Use Error when the problem is real but does not fit a more specific built-in type.
function loadConfig(config) {
if (!config) {
throw new Error("Config is missing");
}
return config;
}This is a good default when the caller needs to know that something failed, but the failure is not specifically about type or range.
Example 2: Wrong type with TypeError
Use TypeError when a value exists but cannot be used as expected.
function repeatName(name) {
if (typeof name !== "string") {
throw new TypeError("name must be a string");
}
return name + " " + name;
}This pattern is common in utility functions and public APIs because it gives an immediate, precise signal about bad input.
Example 3: Out-of-range value with RangeError
Use RangeError when the input type is correct, but the value is not allowed.
function getMonthName(monthIndex) {
if (monthIndex < 0 || monthIndex > 11) {
throw new RangeError("monthIndex must be between 0 and 11");
}
return ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][monthIndex];
}The type is correct because monthIndex is a number, but the allowed range is limited to valid month positions.
Example 4: Reading built-in errors from the platform
You do not always create these errors yourself. JavaScript and the browser also throw them for you.
try {
JSON.parse("not valid JSON");
} catch (error) {
console.log(error instanceof Error); // true
console.log(error.name); // SyntaxError
}Even though this example uses another built-in error type, it shows the same pattern: inspect the error object, then decide how to respond.
5. Practical Use Cases
- Validate function arguments before doing work.
- Reject invalid user input in form-processing logic.
- Signal broken assumptions in library code.
- Guard against impossible states in internal helpers.
- Wrap lower-level failures with a clearer message for the caller.
A typical use case is a public function that accepts a number, string, or object and needs to fail early when the input is wrong.
6. Common Mistakes
Mistake 1: Using TypeError for every problem
Beginners often throw TypeError even when the issue is not about type. That makes error messages less accurate and can confuse people reading logs.
Problem: This code throws a type error for a value that is simply out of range, not the wrong type.
function setVolume(level) {
if (level < 0 || level > 100) {
throw new TypeError("level must be between 0 and 100");
}
}Fix: Use RangeError for numeric limits.
function setVolume(level) {
if (level < 0 || level > 100) {
throw new RangeError("level must be between 0 and 100");
}
}The corrected version communicates the actual kind of failure.
Mistake 2: Assuming Error means a built-in browser problem
Error is not a special browser-only object. It is the base error class you can use yourself anywhere JavaScript runs.
Problem: This code waits for a special runtime failure that never happens, because Error is just a class you can instantiate directly.
try {
const problem = new Error("Oops");
console.log(problem);
} catch (error) {
console.log("This catch will not run unless you throw");
}Fix: Throw the error when you want control flow to stop.
try {
throw new Error("Oops");
} catch (error) {
console.log("Handled:", error.message);
}This works because only throw turns the error object into an exception.
Mistake 3: Writing a message that does not explain the rule
A useful error message tells the caller what was expected and what went wrong. Vague messages make debugging slower.
Problem: The message here does not say what value is invalid or how to fix it.
function parseRating(rating) {
if (typeof rating !== "number") {
throw new TypeError("Invalid value");
}
}Fix: Include the expected type and a clear rule.
function parseRating(rating) {
if (typeof rating !== "number") {
throw new TypeError("rating must be a number between 0 and 5");
}
}The better message makes the failure obvious to anyone who sees it in logs or tests.
7. Best Practices
Practice 1: Choose the most specific built-in error
Specific errors make intent clear and improve debugging. They also help test suites assert the right behavior.
function getPage(pageNumber) {
if (!Number.isInteger(pageNumber)) {
throw new TypeError("pageNumber must be an integer");
}
if (pageNumber < 1) {
throw new RangeError("pageNumber must be at least 1");
}
}Here the type check and the range check are separated, so each failure tells the truth.
Practice 2: Put the useful detail in the message
A good message explains the rule and, when possible, includes the value that failed.
function setPort(port) {
if (!Number.isInteger(port) || port < 1 || port > 65535) {
throw new RangeError(`port must be an integer between 1 and 65535; received ${port}`);
}
}This message helps during testing because it shows both the allowed range and the bad value.
Practice 3: Re-throw errors you cannot handle
If your code cannot recover, do not silently swallow the error. Either handle it meaningfully or pass it upward.
function parseUserAge(value) {
try {
const age = Number(value);
if (Number.isNaN(age)) {
throw new TypeError("age must be numeric");
}
if (age < 0) {
throw new RangeError("age cannot be negative");
}
return age;
} catch (error) {
throw error;
}
}The example shows the structure, but in real code you should only catch when you need to add context, clean up, or recover.
8. Limitations and Edge Cases
- Built-in error names are helpful, but different JavaScript engines may format stack traces differently.
- TypeError is often thrown by the language itself when you access or call something invalid, such as reading a property from null.
- RangeError also appears in built-in APIs, such as invalid array length or recursive call depth limits.
- Not every invalid input should be a thrown error; sometimes returning null, undefined, or a result object is better for expected conditions.
- The same input may deserve different errors depending on context. A library API and an internal helper may make different tradeoffs.
A common search phrase is “TypeError: Cannot read properties of undefined”. That message usually means code tried to access a property on a missing value, not that the variable name itself is wrong.
9. Practical Mini Project
In this small example, we will build a validator that checks a user profile object and throws the right built-in error type for each failure.
function validateProfile(profile) {
if (typeof profile !== "object" || profile === null) {
throw new TypeError("profile must be an object");
}
if (typeof profile.name !== "string") {
throw new TypeError("profile.name must be a string");
}
if (!Number.isInteger(profile.age)) {
throw new TypeError("profile.age must be an integer");
}
if (profile.age < 0 || profile.age > 130) {
throw new RangeError("profile.age must be between 0 and 130");
}
return true;
}
try {
validateProfile({ name: "Ava", age: 34 });
console.log("Profile is valid");
} catch (error) {
console.error(error.name, error.message);
}This mini project shows how the three error types work together: TypeError covers the wrong shape or kind of value, and RangeError covers values that are valid in type but not valid in bounds.
10. Key Points
- Error is the general-purpose built-in error class.
- TypeError means the value cannot be used in the required way.
- RangeError means the value is outside the permitted range.
- Use specific error types so logs, tests, and API consumers can understand failures faster.
- Good error messages should explain what was expected and what was received.
11. Practice Exercise
Build a function called clampRating that validates a rating value.
- It should throw a TypeError if the input is not a number.
- It should throw a RangeError if the number is below 1 or above 5.
- It should return the rating if it is valid.
Expected output: a valid number between 1 and 5 returns unchanged, while invalid input throws the appropriate built-in error.
Hint: check the type first, then check the allowed range.
function clampRating(rating) {
if (typeof rating !== "number" || Number.isNaN(rating)) {
throw new TypeError("rating must be a number");
}
if (rating < 1 || rating > 5) {
throw new RangeError("rating must be between 1 and 5");
}
return rating;
}
// Example usage
console.log(clampRating(4)); // 412. Final Summary
JavaScript error types give you a standard way to describe failures. Error is the general base class, TypeError is for wrong or unusable values, and RangeError is for values outside the allowed limits.
Choosing the right error type makes your code easier to debug and your APIs easier to use. It also helps you write better validation because the error itself tells the caller what kind of mistake happened.
As you continue learning error handling, practice throwing and catching these errors in small validation functions. That habit will make your runtime checks clearer and your debugging faster.