AZ.dev

Fail a Node script without cutting off its output

| node: 18+

Set process.exitCode and let the script end on its own. Calling process.exit() stops the process immediately, before pending writes have flushed.

if (failures.length > 0) {
  console.error(`${failures.length} checks failed`);
  process.exitCode = 1;
}

When the event loop drains, Node exits with that code. Everything written to stdout and stderr gets there first.

Why exit() loses output

Writes to a pipe or a file are asynchronous. console.log hands the bytes to the stream and returns; the flush happens on a later tick. process.exit(1) doesn’t wait for that tick. Run the script in a terminal and it looks fine, because a TTY write is synchronous. Run it in CI, where stdout is a pipe, and the last lines vanish, which is usually the error message you needed.

When exit() is right

A hung process that you’ve already reported on, such as a server that failed to bind and now has open handles keeping the loop alive. Even then, write the message, then exit on the next tick:

console.error("Could not bind port 3030");
setImmediate(() => process.exit(1));

Gotchas

process exit exitCode stdout cli

This entry is one card on a printable cheat sheet:

Node.js Essentials Cheat Sheet

Was this helpful?

Related Entries

Reproduce Railway's npm ci locally with the exact npm versionSerialize per-user check-then-write flows with pg_advisory_xact_lock(hashtext(id))Content-hash dedup that restores a soft-deleted row must re-run quota and limit checksA storage URL builder and its static file handler must share one prefix constantGive a fetch call a timeout