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
componentDidCatchreceives 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 / Method | What it gives you |
|---|---|
.message | Human-readable description of what went wrong |
.name | Error type as a string — 'Error', 'TypeError', etc. |
.stack | Full stack trace — file, line number, call chain |
.cause | The original error that triggered this one (ES2022) |
instanceof | Check the error type in a catch block |
extends Error | Create custom error classes with domain-specific properties |
Built-in types
| Type | When it’s thrown |
|---|---|
| Error | General-purpose — the base type |
| TypeError | Wrong type — calling non-function, accessing property of null |
| ReferenceError | Variable doesn’t exist in scope |
| SyntaxError | Code can’t be parsed — malformed JSON, bad syntax |
| RangeError | Value outside allowed range — invalid array length, stack overflow |
| URIError | Bad 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, .causetypeof doesn’t work
const err = new Error('fail')
typeof err // 'object' — not useful
err instanceof Error // true — this is how you checkRelated
- Closures — error factories use closures to capture context
- Promises —
.catch()receives Error objects;causechains pair well with async - try/catch — the primary way you interact with Error objects
Last updated on