Frontend Development 15 min read

Understanding Errors and Exceptions in JavaScript

This article explains JavaScript error objects, their properties, common built‑in error types, how to create and throw custom errors, and demonstrates synchronous and asynchronous error handling techniques—including try/catch, generators, promises, timers, event listeners, and the onerror handler—complete with code examples.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Understanding Errors and Exceptions in JavaScript

What are errors in programming

During development we often encounter situations where we need to stop a program or notify the user of an undesirable condition.

Attempting to open a non‑existent file

Network connection lost

User input contains invalid characters

In such cases we can define custom errors ourselves or let the engine provide built‑in error objects, then use their messages to inform the user or halt execution.

What are errors in JavaScript

In JavaScript an error is an object. To create one you can use the Error constructor:

const err = new Error('Oops, something went wrong!')

You can also omit the new keyword:

const err = Error('Oops, something went wrong!')

An error object has three main properties:

message : the error message string

name : the type of error

stack : the stack trace at the point the error was created

For example, creating a TypeError yields a name of "TypeError" and the provided message:

const wrongType = TypeError("Oops, something went wrong!")

wrongType.message // "Oops, something went wrong!"
wrongType.name    // "TypeError"

Many types of errors in JavaScript

JavaScript defines several built‑in error constructors, such as:

Error

EvalError

InternalError

RangeError

ReferenceError

SyntaxError

TypeError

URIError

All of these are actual constructors that return a new error object. In practice the most frequently used are Error and TypeError .

Many errors are thrown directly by the JavaScript engine, for example InternalError or SyntaxError . Reassigning a const variable also triggers a TypeError :

const name = "Frontend Guru"
name = "Backend Master"
// TypeError: Assignment to constant variable.

A SyntaxError typically occurs when a keyword is misspelled:

var x = '33';
// SyntaxError: Unexpected identifier

Or when await is used outside an async function:

function wrong(){
    await 99;
}
wrong();
// SyntaxError: await is only valid in async function

Another TypeError example is accessing a non‑existent DOM element:

Uncaught TypeError: button is null

Beyond these built‑ins, browsers also expose DOMException (and the now‑deprecated DOMError ) for Web API errors. For instance:

document.body.appendChild(document.cloneNode(true));
// Uncaught DOMException: Node.appendChild: May not add a Document as a child

What is an exception?

Many developers treat errors and exceptions as the same thing, but an error object only becomes an exception when it is thrown.

To raise an exception in JavaScript you use the throw keyword:

const wrongType = TypeError("Oops, something went wrong!")
throw wrongType;

Short forms are also possible:

throw TypeError("Oops, something went wrong!")

Or even throwing non‑error values (though this is discouraged):

throw Symbol();
throw 33;
throw "Error!";
throw null;

It is best practice to always throw proper error objects so that other code can rely on error.message and error.stack for debugging.

What happens when we throw an exception?

An exception propagates up the call stack like an elevator: it bubbles until it is caught by a try/catch block, otherwise the program terminates.

function toUppercase(str) {
  if (typeof str !== "string") {
    throw TypeError("Argument must be a string");
  }
  return str.toUpperCase();
}

toUppercase(4);
// Uncaught TypeError: Wrong type given, expected a string
//     at toUppercase (http://localhost:5000/index.js:3)
//     at
(http://localhost:5000/index.js:9)

The stack trace can also be inspected via the error object's stack property. If an exception is not caught, the script crashes.

Synchronous error handling

Synchronous code runs in the order it is written, making its error handling straightforward.

Regular function error handling

Use try/catch/finally to capture exceptions thrown by synchronous functions:

try {
  toUppercase(4);
} catch (error) {
  console.error(error.message);
} finally {
  // optional cleanup
}

Using generator functions to handle errors

Generator functions ( function* ) can pause and resume execution with yield . They return an iterator object that supports next() , throw() , and can be iterated with for...of .

function* generate() {
  yield 33;
  yield 99;
}

const go = generate();
const first = go.next().value; // 33
const second = go.next().value; // 99

You can inject an error into a generator with throw() :

function* generate() {
  yield 33;
  yield 99;
}

const go = generate();
go.next(); // 33
go.throw(Error("I want to stop you!")); // throws inside generator

Inside the generator you can catch the injected error with try/catch :

function* generate() {
  try {
    yield 33;
    yield 99;
  } catch (error) {
    console.error(error.message);
  }
}

Or iterate with for...of and handle errors externally:

function* generate() {
  yield 33;
  yield 99;
  throw Error("I want to stop you!");
}

try {
  for (const value of generate()) {
    console.log(value);
  }
} catch (error) {
  console.log(error.message);
}
// Output:
// 33
// 99
// I want to stop you!

Asynchronous error handling

JavaScript is fundamentally synchronous, but Web APIs introduce asynchronous behavior (timers, events, Promises, etc.). Error handling for asynchronous code differs from synchronous handling.

Timer error handling

Errors thrown inside setTimeout cannot be caught by an outer try/catch because the callback runs later on a separate call stack:

function failAfterOneSecond() {
  setTimeout(() => {
    throw Error("Something went wrong!");
  }, 1000);
}

// This try/catch will NOT catch the error
try {
  failAfterOneSecond();
} catch (e) {
  console.error(e.message);
}

The proper way is to handle the error inside the asynchronous callback or to use a Promise.

Event error handling

Event listeners are also asynchronous. Throwing inside an event handler is not caught by surrounding try/catch :

const button = document.querySelector("button");

button.addEventListener("click", function() {
  throw Error("Can't touch this button!");
});

Instead, you can wrap the handler logic in its own try/catch or use addEventListener with error‑handling code.

How about onerror?

HTML elements expose an onerror event for resource loading failures (e.g., missing images or scripts). You can capture such errors like this:

const image = document.querySelector("img");
image.onerror = function(event) {
  console.log(event);
};

A more modern approach uses addEventListener :

image.addEventListener("error", function(event) {
  console.log(event);
});

This is useful for handling missing resources, but it is unrelated to throw or try/catch mechanisms.

frontendJavaScriptError handlingAsyncGeneratorsexceptions
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.