JavaScript Runtime Semantics

Errors, Exceptions & Stack Traces

JavaScript can throw any value, but production code should throw Error objects or subclasses so stack traces, names, causes, and handling stay useful.
  • Thrown values interrupt normal control flow
  • Throw Error objects, not strings
  • Use cause to preserve lower-level failures
  • Async errors flow through Promises
  • Domain errors should be distinguishable
Custom domain error
class ValidationError extends Error {
  constructor(message, details) {
    super(message)
    this.name = "ValidationError"
    this.details = details
  }
}

try {
  saveUser(input)
} catch (err) {
  if (err instanceof ValidationError) {
    showFieldErrors(err.details)
  } else {
    throw err
  }
}
A domain-specific error lets callers handle expected failure differently from bugs.
Error handling choices
PatternUse forWatch out
throw ErrorExceptional failureMust be caught at boundary
Result objectExpected recoverable failureCallers must check
Error subclassDomain-specific handlingKeep inheritance simple
causeWrap lower-level errorPreserve original context
Sources
  • MDN JavaScript Guide and ReferenceControl flow and error handling; Error objects
  • The Modern JavaScript TutorialError handling
  • Node.js Documentation and Learn Node.jsErrors and diagnostics