# Throwing Your Own Errors

When a function gets a value it can't use, throw new Error with a message that says what was wrong, make your own error class with extends Error for the problems your program knows about, and return a value instead when there's no mistake to report.

Journeyman · JavaScript · Software Development · Updated November 1, 2026

## After this lesson you can

- Throw an Error with a clear message when a function gets a value it can't use
- Make a custom error class with extends Error and tell it apart with instanceof
- Choose between throwing an error and returning a value

## Key takeaways

- throw new Error("...") stops the function at once and hands the error to the nearest catch.
- A helpful message says what was wrong, shows the value that came in and says what would work.
- A class such as ServingsError extends Error gives your errors their own name. instanceof tells them apart in a catch block.
- A catch block that only handles one kind of error throws the others on with throw error.
- Return a value for a normal answer, even "nothing found". Throw when the caller made a mistake or the job can't be done.

Every function you write gets used by someone: other parts of your program, a teammate, or you in six months. Sooner or later one of them calls it with a value that makes no sense, like scaling a recipe to `-2` servings. JavaScript won't always complain. Sometimes it hands back a wrong answer, and the bug shows up three steps later, far from where it started. In this lesson your functions stop bad values at the door with a clear message: the same thing `JSON.parse` does when it gets text that isn't JSON.

## The problem: wrong answers, no complaints

Here's the recipe scaler's core: divide by the servings the card makes, multiply by the servings you want.

```javascript
function scaleAmount(amount, fromServings, toServings) {
  return (amount / fromServings) * toServings;
}

console.log(scaleAmount(2, 4, 10));
console.log(scaleAmount(2, 4, -2));
console.log(scaleAmount(2, 4, "ten"));
```

```text
5
-1
NaN
```

2 cups of flour for 4 becomes 5 cups for 10: right. But *-1 cups* and *NaN cups* (`NaN` is read "not a number", from *Types and Converting Between Them*) are nonsense, and the program carries on as if they were fine. A shopping list would print *Buy NaN cups of flour*.

## throw: refuse the value, out loud

A good restaurant kitchen doesn't quietly cook a wrong order. It sends the ticket back: *We can't make this, we're out of eggs.* Your function can do the same with **`throw`** (read "throw"): it stops the function at once and hands an error to the nearest `catch`.

You make the error with **`new Error("message")`**, the same kind of error object `JSON.parse` throws. Together, `throw new Error("...")` is read "throw new error".

```javascript
function checkServings(servings) {
  if (!Number.isInteger(servings) || servings <= 0) {
    throw new Error(`Servings must be a whole number above 0, but got ${servings}.`);
  }
  return servings;
}

function scaleAmount(amount, fromServings, toServings) {
  checkServings(fromServings);
  checkServings(toServings);
  return (amount / fromServings) * toServings;
}

try {
  console.log(scaleAmount(2, 4, 10));
  console.log(scaleAmount(2, 4, -2));
  console.log("This line is skipped.");
} catch (error) {
  console.log(error.message);
}
```

```text
5
Servings must be a whole number above 0, but got -2.
```

`Number.isInteger(servings)` is `true` only for a whole number: `10` yes, `2.5` no, `"ten"` no. The `!` (read "not") flips it, and `||` (read "or") joins the two checks, as in *Combining Conditions with And, Or and Not*. When `throw` runs, nothing after it in `checkServings` runs, nothing after the call in `scaleAmount` runs, and the line that was waiting for the answer is skipped too. JavaScript jumps to the `catch`.

## A message that helps

The message is for a person: the one who reads it in the Console, or sees it on the page. A helpful message answers three questions: what was wrong, what value came in, and what would work.

| Not much help | Helpful |
|---|---|
| `Error` | `Servings must be a whole number above 0, but got -2.` |
| `Invalid input` | `Unknown unit "pinch". Use cups, tbsp, tsp or ml.` |
| `Something went wrong` | `The recipe card has no ingredients list.` |

**Try it.** Make `scale.js` with the code above. Call `scaleAmount` with `"ten"`, then `2.5`, then `0`, each in its own `try`. Does every message tell you what to fix?

## Your own kind of error

Each error object has a `name`, and so far yours all say `Error`. When a program has its own kinds of problems, it can give them their own names, the way a car's dashboard has a fuel light and an oil light instead of one light that says *problem*. You make a new kind of error with a class that **extends** `Error`, as in *Inheritance with extends and super*:

```javascript
class ServingsError extends Error {
  constructor(message) {
    super(message);
    this.name = "ServingsError";
  }
}

function checkServings(servings) {
  if (!Number.isInteger(servings) || servings <= 0) {
    throw new ServingsError(`Servings must be a whole number above 0, but got ${servings}.`);
  }
  return servings;
}

try {
  checkServings("ten");
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
  console.log(error instanceof ServingsError);
  console.log(error instanceof Error);
}
```

```text
ServingsError: Servings must be a whole number above 0, but got ten.
true
true
```

`super(message)` runs `Error`'s own constructor, which keeps the message (and the stack). `this.name` gives the error its name. This is called a **custom error**. The word **`instanceof`** (read "instance of") asks whether an object was made from a class, or from a class that extends it. A `ServingsError` is an `Error` too, so both lines print `true`.

## Catch the errors you can handle

With its own name, a catch block can tell a `ServingsError` (the person typed something wrong: ask again) from any other error (a bug: let it through). This part of a catch block handles one kind and **throws the rest on** with `throw error`, so a bug is never hidden:

```javascript
} catch (error) {
  if (error instanceof ServingsError) {
    console.log(`Please pick the servings again. ${error.message}`);
  } else {
    throw error;
  }
}
```

The `else` throws the same error again, so it travels on to the next `catch` further out, or stops the program with its stack trace, where you'll see it and fix it.

## Throw, or return a value?

Not every "no" is an error. Ask the pantry for saffron and it says "we don't have any": that's a normal answer, not a mistake. Here `find` (from *Finding Things in an Array*) returns `undefined` when nothing matches, and the caller checks for it:

```javascript
const pantry = ["flour", "sugar", "eggs", "butter"];

function findIngredient(name) {
  return pantry.find((item) => item === name);
}

console.log(findIngredient("sugar"));
console.log(findIngredient("saffron"));
```

```text
sugar
undefined
```

A rule of thumb:

| The situation | What to do | Example |
|---|---|---|
| A normal answer, even "nothing" | Return a value: `undefined`, `null`, `false` or an empty list `[]` | No recipe matches a search |
| The caller made a mistake | Throw | `-2` servings, a unit called `"pinch"` |
| The job can't be done at all | Throw | A recipe card with no ingredients |

When you're not sure, ask: *should the caller have known better?* If yes, throw. If the answer is a normal part of the job, return it.

## Check yourself

3 questions to try on the lesson page.

## So what

The code you write gets called with surprises. A function that throws a clear error at the first bad value turns a mystery three steps later into one sentence that says what to fix, and that's what every good library you'll use, from `JSON.parse` on, does for you.

## Key terms

- [throw](https://www.ask-codey.com/glossary/throw-javascript)
- [Custom Error](https://www.ask-codey.com/glossary/custom-error)
- [Error](https://www.ask-codey.com/glossary/error)
- instanceof
- [extends](https://www.ask-codey.com/glossary/extends)

## Cheat sheets

- [Throwing Your Own Errors](https://www.ask-codey.com/cheat-sheets/javascript-errors-throwing-your-own-cheat-sheet)

## Related

- [Handling Errors with try, catch and finally](https://www.ask-codey.com/lessons/javascript-errors-try-catch-finally)

Source: https://www.ask-codey.com/lessons/javascript-errors-throwing-your-own
