Skip to content
Latchkey

Node "Error: write EPIPE" in CI - Handle the Broken Pipe

EPIPE means your process wrote to a pipe whose reader has gone away. In CI it often happens when stdout is piped to a command that exits early, like head.

What this error means

A node process throws Error: write EPIPE, frequently from process.stdout, when the reader of a pipe closes before all output is written.

node
Error: write EPIPE
    at afterWriteDispatched (node:internal/stream_base_commons:160:15)
    at writeGeneric (node:internal/stream_base_commons:151:3) {
  errno: -32, code: 'EPIPE', syscall: 'write'
}

Diagnose it: the shell in CI is not your shell

Package scripts run under a different shell, a different PATH, and a non-interactive environment on a runner. Most scripts that fail only in CI are relying on something the login shell gave them locally: a tool on PATH, an environment variable from a dotfile, or a TTY.

Terminal
# what the script can actually see
npm run env | grep -E "^(PATH|NODE_ENV|CI)=" 

# is the binary on PATH for the script, not just for you?
npm exec -- which <tool> || echo "not resolvable from npm scripts"

# run the exact script with tracing
sh -x -c "$(node -p "require('./package.json').scripts.build")"

Common causes

A downstream reader closed the pipe early

Piping node output into a command like head that exits after a few lines closes the read end, so further writes hit EPIPE.

Writing to a socket the peer already closed

The remote end disconnected, and a continued write to that stream raises EPIPE.

How to fix it

Handle the stream error

  1. Attach an error listener to the writable stream.
  2. Exit cleanly on EPIPE instead of letting it become an uncaught exception.
JavaScript
process.stdout.on('error', (err) => {
  if (err.code === 'EPIPE') process.exit(0);
});

Avoid truncating pipes in CI

  1. Remove pipes that close early (head, less) from CI commands.
  2. Write full output to a file or let it complete.

Make failures fail the job

A multi-command script can report success while a middle command failed, which produces the worst kind of CI result: a green build that shipped something broken.

.github/workflows/ci.yml
# pipefail is NOT set by default in every runner shell
- name: Build
  shell: bash
  run: |
    set -euo pipefail
    npm run build | tee build.log

How to prevent it

  • Attach error handlers to long-lived writable streams, avoid piping CI output through early-exiting readers, and treat EPIPE as a normal shutdown condition.

Frequently asked questions

What causes Node "Error: write EPIPE" in CI?
There are 2 common causes: a downstream reader closed the pipe early and writing to a socket the peer already closed. Piping node output into a command like head that exits after a few lines closes the read end, so further writes hit EPIPE.
How do I fix Node "Error: write EPIPE" in CI?
There are 2 fixes depending on which cause you have: handle the stream error and avoid truncating pipes in ci. Work through them in order, since the first is the most common.
What does Node "Error: write EPIPE" in CI actually mean?
A node process throws Error: write EPIPE, frequently from process.stdout, when the reader of a pipe closes before all output is written.
How do I stop Node "Error: write EPIPE" in CI happening again?
Attach error handlers to long-lived writable streams, avoid piping CI output through early-exiting readers, and treat EPIPE as a normal shutdown condition.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card