Error handling
Error handling in JavaScript looks simple — everyone knows try/catch — yet this is where the trickiest interview questions hide. throw does not "return" an error; it unwinds the stack. finally can override a return from try. A try/catch will not catch an error from a setTimeout callback, because that runs later on a new stack. The difference between a synchronous and an asynchronous failure is the divide between junior and senior here.
The topic breaks into six layers: the Error object and its subtypes, the mechanics of throw and propagation, the try/catch/finally trio, custom error classes, asynchronous errors (promises, async/await, global handlers), and strict mode, which turns silent failures into explicit exceptions.
Topic map
- Error object and subtypes —
name,message,stack, and the built-inTypeError/RangeError/SyntaxError/ReferenceError. - The throw statement — what
throwdoes, what you can throw, propagation up the stack, and rethrowing. - try/catch/finally — the role of each block, the optional
catchbinding, and the dangerousfinallysemantics. - Custom error classes —
class extends Error,super(message),this.name, and thecauseoption. - Asynchronous errors — why
try/catchmisses a deferred callback,.catch,await, andunhandledrejection. - Strict mode —
'use strict'turns silent failures into errors; modules and classes are always strict.
Common traps
| Mistake | Consequence |
|---|---|
Expecting try/catch to catch a throw from setTimeout | The error is uncaught — the callback ran on a new stack |
Putting a return in finally | Silently discards the return and the error from try/catch |
Wrapping a promise in try/catch without await | The rejection escapes — the synchronous block has already finished |
Forgetting super(message) in a custom error class | The base message and stack are not set up |
Treating stack as a standard property | It is non-standard; you cannot rely on the format |
Thinking this in a plain call is the global | In strict mode this is undefined |
Interview relevance
This is a senior topic, and the questions here are diagnostic. throw-in-setTimeout checks whether you understand the event loop; return-in-finally checks whether you know the execution order; custom errors check whether you command prototypes and instanceof.
Typical checks:
- The
Errorproperties (name/message/stack), the built-in subtypes, and that they inherit fromError. - That
throwunwinds the stack to the nearestcatchrather than returning a value. - The semantics of
finally— it always runs, and areturn/throwinside it overrides the pending value. - Why an asynchronous failure is not caught by a synchronous
try/catch, and how to handle it via.catch/await.
Common wrong answer: "try/catch catches any error inside the block". In fact it guards only the synchronous stack active when it runs. A timer, promise, or event-handler callback runs later — on a new stack where that try no longer exists.