Question presented to candidate: "A Promise rejects and nothing ever calls .catch() on it. Does that crash your Node process today, and has that behavior always been true?"
What a strong answer should cover:
process.on("uncaughtException", ...)andprocess.on("unhandledRejection", ...)are two distinct events, for two distinct failure shapes: a genuine synchronous throw that propagates all the way up uncaught, versus a rejected Promise that no code ever attached a.catch()/await-try/catchto.- 📌 Verified, version-relevant behavior: with no handler registered at all, an unhandled Promise rejection crashes the process immediately, with a nonzero exit code — this is Node's modern default (since Node 15), not merely a warning as in some older versions; a precise answer does not assume the older, warn-only behavior without checking the actual Node version in use.
- Both events are correctly understood as a last-resort safety net, not a general-purpose error-handling mechanism — the right place to handle an error is as close as possible to where it actually occurs (a
try/catch, a.catch(), a centralized Express error middleware), not by relying on a process-wide handler to catch everything after the fact. - The standard, correct pattern for these handlers: log the error with full context, then deliberately exit the process (
process.exit(1), or let the crash proceed) so a supervisor (a container orchestrator,pm2,systemd) restarts it fresh — connecting directly to the operational-vs-programmer-errors question, since reaching this handler at all generally signals an unknown, untrusted program state. - A precise answer names the real, common cause of
unhandledRejectionspecifically: anasyncfunction called withoutawaiting it and with no.catch()attached to the resulting Promise — the call still runs, but nothing observes a later rejection. process.on("uncaughtExceptionMonitor", ...)is a related, less commonly known event — it fires alongsideuncaughtExceptionwithout suppressing Node's own default handling, useful specifically for observability/logging without altering the crash behavior itself.
Clarifying questions expected:
- "Which Node version — does the codebase rely on older warn-only unhandledRejection behavior, or the current terminate-by-default behavior?" — genuinely different, and worth confirming rather than assuming.
- "Is the goal catching these as a last resort, or actually preventing them by fixing the missing
.catch()/try/catchat the source?" — the latter is almost always the better fix.
Code / implementation expected: Yes — demonstrating both events firing distinctly, and the real crash-with-no-handler default behavior, is the concrete, convincing part of the answer.