Skip to main content

The throw statement in JavaScript

The throw statement is used to create and throw an error, that is, to forcibly stop execution and hand control to the nearest catch block, if there is one. It is the main way for a function to report a situation it cannot handle correctly.

Theory

TL;DR

  • throw expression; immediately stops the execution of the current function.
  • JavaScript then looks for the nearest try...catch to catch that value.
  • Any value can be thrown: a string, a number, an object. The right choice, though, is Error or one of its subclasses.
  • The subclasses TypeError, ReferenceError, SyntaxError, RangeError and EvalError make the nature of the problem explicit.
  • A finally block always runs, whether or not there was an error.

Quick example

javascript
throw new Error("Something went wrong!");

When the interpreter meets throw, execution of the current function stops immediately, and JavaScript starts looking for the nearest try...catch block to catch this error. If there is no such block, the error reaches the top of the stack and the program (or the current task) fails.

Syntax and what can be thrown

javascript
throw expression;

Where expression is any value, though most often it is an error object (Error).

Handling it with try...catch:

javascript
try { throw new Error("Server connection error!"); } catch (error) { console.log("Caught an error:", error.message); }

Result:

Caught an error: Server connection error!

JavaScript does not require you to throw an error object specifically; you can throw anything:

javascript
throw "Just a string"; throw 404; throw { message: "Data error", code: 123 };

By convention, however, it is always better to use Error or its subclasses: only they are guaranteed to carry a name, a message and a stack trace.

Built-in error types

  • Error is the base type
  • TypeError
  • ReferenceError
  • SyntaxError
  • RangeError
  • EvalError

An example with a specific type:

javascript
function divide(a, b) { if (b === 0) { throw new RangeError("Division by zero!"); } return a / b; } try { divide(5, 0); } catch (err) { console.error(err.name + ": " + err.message); }

Result:

RangeError: Division by zero!

The chosen error type lets the catch block tell situations apart with err instanceof RangeError and react differently to each.

How it works together with try...catch...finally

javascript
try { console.log("Starting"); throw new Error("Failure!"); } catch (e) { console.log("Caught:", e.message); } finally { console.log("This block always runs"); }

Result:

Starting Caught: Failure! This block always runs

A summary table:

What it doesDescription
throwStops execution and throws an error
What can be thrownAny value (but Error is recommended)
Handled bytry...catch
After throwCode in the same block does not run
The finally blockAlways runs, even on a throw

Common mistakes

  • Throwing a string instead of an Error. The catch block then has neither message nor stack, and the logs become useless. Write throw new Error("...").
  • Forgetting new. throw Error("...") still works, because Error can be called without new, but a custom error class called without new will not behave as expected.
  • Expecting code after throw to run. The remaining statements in the same block are unreachable.
  • Swallowing the error with an empty catch. A catch (e) {} block hides the problem; either handle it or rethrow it with throw e.
  • Putting a return inside finally. It overrides both the value being returned and the error being thrown, so the problem silently disappears.
  • Assuming try...catch catches asynchronous errors. A throw inside setTimeout, or an unhandled promise rejection outside the block, is not caught: for promises you need await inside the try, or a .catch().

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.