Skip to Content

Error

The built-in object JavaScript throws when something goes wrong. You can catch it, inspect it, and create your own.

When to use it

  • Wrapping risky code — network calls, JSON parsing, DOM access
  • Custom errors — domain-specific failures (ValidationError, AuthError)
  • Rethrowing — catch, log, then throw a more meaningful error up the chain
  • Error boundaries — React’s componentDidCatch receives an Error
  • API responses — converting HTTP failures into typed errors

Anatomy

const err = new Error('something broke') err.message // 'something broke' — what went wrong err.name // 'Error' — the error type (Error, TypeError, etc.) err.stack // 'Error: something broke\n at ...' — full stack trace string err.cause // undefined — optional, set via { cause } option (ES2022)

At a glance

Property / MethodWhat it gives you
.messageHuman-readable description of what went wrong
.nameError type as a string — 'Error', 'TypeError', etc.
.stackFull stack trace — file, line number, call chain
.causeThe original error that triggered this one (ES2022)
instanceofCheck the error type in a catch block
extends ErrorCreate custom error classes with domain-specific properties

Built-in types

TypeWhen it’s thrown
ErrorGeneral-purpose — the base type
TypeErrorWrong type — calling non-function, accessing property of null
ReferenceErrorVariable doesn’t exist in scope
SyntaxErrorCode can’t be parsed — malformed JSON, bad syntax
RangeErrorValue outside allowed range — invalid array length, stack overflow
URIErrorBad URI encoding/decoding

1. Simple — catch and inspect

try { JSON.parse('not json') } catch (err) { err.name // 'SyntaxError' — the specific error type that was thrown err.message // 'Unexpected token o in JSON...' — human-readable description err.stack // full trace — file, line, and call stack that led here }

2. Intermediate — custom error

class ValidationError extends Error { constructor(field, message) { super(message) // sets this.message this.name = 'ValidationError' // override default 'Error' name this.field = field // custom property — which field failed } } try { throw new ValidationError('email', 'Invalid email format') } catch (err) { err.name // 'ValidationError' — your custom type, not generic 'Error' err.field // 'email' — the domain-specific context you added err.message // 'Invalid email format' if (err instanceof ValidationError) { // handle validation errors differently from other errors } }

3. Advanced — error cause chain

async function fetchUser(id) { try { const res = await fetch(`/api/users/${id}`) if (!res.ok) { // wrap the HTTP failure with context about what you were trying to do throw new Error(`Failed to fetch user ${id}`, { cause: new Error(`HTTP ${res.status}`), // original error attached as cause }) } return await res.json() } catch (err) { // re-throw with even more context — errors chain via cause throw new Error('User lookup failed', { cause: err }) } } try { await fetchUser(42) } catch (err) { err.message // 'User lookup failed' — the outermost context err.cause.message // 'Failed to fetch user 42' — one level deeper err.cause.cause // Error('HTTP 404') — the root cause }

cause (ES2022) lets you wrap errors without losing the original. No more swallowed stack traces.


Gotchas

Catching non-errors

// JavaScript lets you throw ANYTHING — not just Error objects throw 'oops' // string — no stack trace, no .name, no .cause throw 404 // number throw { bad: true } // plain object // always throw actual Errors so catch blocks have a consistent shape throw new Error('oops') // has .message, .name, .stack, .cause

typeof doesn’t work

const err = new Error('fail') typeof err // 'object' — not useful err instanceof Error // true — this is how you check

  • Closures — error factories use closures to capture context
  • Promises.catch() receives Error objects; cause chains pair well with async
  • try/catch — the primary way you interact with Error objects
Last updated on