# @typescript-eslint/only-throw-error

> Disallow throwing values that are not `Error` objects

You can `throw` any value, but only an `Error` records the stack where it was created. Code that catches it also expects an `Error`. With `throw "not found"`, `error.message` is `undefined` and `error instanceof Error` is `false`.

By default, you can throw values of type `any` or `unknown`, and you can rethrow an error that you caught.

`bun lint --type-aware` turns this rule on in TypeScript files.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. This rule needs types, so turning it on makes `bun lint` type check your code first.

```toml bunfig.toml
[lint.rules]
"@typescript-eslint/only-throw-error" = "error" # or "warn"
```

Every option, set to its default:

```toml bunfig.toml
[lint.rules]
"@typescript-eslint/only-throw-error" = ["error", {
  allowThrowingAny = true,
  allowThrowingUnknown = true,
  allowRethrowing = true,
  allow = [], # list of strings or objects
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad {"count": 3} */}
```ts
function load(path: string, status: number) {
  if (!path) throw "path is required";
  if (status === 404) throw { status };
  throw undefined;
}
```

Not reported:

{/* good */}
```ts
class HttpError extends Error {
  constructor(public status: number) {
    super(`Request failed with ${status}`);
  }
}

function load(path: string, status: number) {
  if (!path) throw new Error("path is required");
  throw new HttpError(status);
}
```

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `allowThrowingAny` | `true` | Allow throwing a value of type `any`. |
| `allowThrowingUnknown` | `true` | Allow throwing a value of type `unknown`. |
| `allowRethrowing` | `true` | Allow throwing the `error` from `catch (error)`, from `.catch(error => ...)`, and from the second callback of `.then()`, whatever its type. |
| `allow` | `[]` | Other types you can throw. |

{/* bad {"options": [{"allowThrowingAny": false}]} */}
```ts
function fail(reason: any) {
  throw reason;
}
```

In strict mode, the `error` in a `catch` is `unknown`. With `allowThrowingUnknown: false`, you can still throw it again:

{/* good {"options": [{"allowThrowingUnknown": false}]} */}
```ts
function parse(text: string): unknown {
  try {
    return JSON.parse(text);
  } catch (error) {
    console.error("invalid JSON");
    throw error;
  }
}
```

{/* bad {"options": [{"allowThrowingUnknown": false, "allowRethrowing": false}]} */}
```ts
function parse(text: string): unknown {
  try {
    return JSON.parse(text);
  } catch (error) {
    console.error("invalid JSON");
    throw error;
  }
}
```

Each `allow` entry is a type name, or an object that also says where the type comes from: `{ "from": "file", "name": "Redirect" }` for your own code, `{ "from": "lib", "name": "Response" }` for a built-in type, or `{ "from": "package", "name": "Redirect", "package": "my-router" }`.

{/* good {"options": [{"allow": [{"from": "file", "name": "Redirect"}]}]} */}
```ts
class Redirect {
  constructor(public url: string) {}
}

throw new Redirect("/login");
```
