JavaScript Error Handling

Throw, catch, and recover from errors in synchronous and asynchronous code

Overview

Errors signal that something unexpected happened, and JavaScript uses throw to raise them and try/catch to handle them. The Error object carries a message and a stack, and you can extend it to create meaningful custom types. Robust handling means catching only what you can recover from and letting the rest propagate.

Syntax / Usage

Wrap risky code in try, handle failures in catch, and run cleanup in finally. Rejected promises are caught with .catch() or with try/catch inside async functions.

function parseConfig(json) {
  try {
    return JSON.parse(json)
  } catch (err) {
    console.error('Invalid config:', err.message)
    return {}
  } finally {
    console.log('parse attempt finished')
  }
}

// Throwing your own error
function withdraw(balance, amount) {
  if (amount > balance) {
    throw new RangeError('Insufficient funds')
  }
  return balance - amount
}

Examples

Define a custom error class to distinguish failure types:

class ValidationError extends Error {
  constructor(field, message) {
    super(message)
    this.name = 'ValidationError'
    this.field = field
  }
}

function validate(user) {
  if (!user.email) throw new ValidationError('email', 'Email required')
}

try {
  validate({})
} catch (err) {
  if (err instanceof ValidationError) console.log(err.field) // 'email'
  else throw err // rethrow unknown errors
}

Handle asynchronous errors with async/await:

async function loadUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`)
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    return await res.json()
  } catch (err) {
    console.error('Failed to load user:', err.message)
    return null
  }
}

Common Mistakes

  • Swallowing errors with an empty catch {} block, hiding real bugs
  • Catching everything and continuing as if nothing failed
  • Throwing strings or plain objects instead of Error instances (losing the stack)
  • Forgetting that throw inside a setTimeout callback cannot be caught by an outer try
  • Not handling promise rejections, causing unhandled rejection warnings

See Also

promises async-await javascript-event-loop