stackademic

The leading education platform for anyone with an interest in software development.

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