winston logger transport "write EPIPE" in CI
EPIPE means a write went to a pipe whose reading end already closed. With winston, a Console or Stream transport keeps writing to stdout/stderr (or a custom stream) after the consumer, such as a piped tee or head, has exited, and Node raises "write EPIPE".
What this error means
A CI step logs "Error: write EPIPE" with a stack through @winstonjs/winston-transport and process.stdout.write, sometimes crashing the process after the test output was piped elsewhere.
Error: write EPIPE
at afterWriteDispatched (node:internal/stream_base_commons:...)
at writeGeneric (node:internal/stream_base_commons:...)
emitted from winston Console transportCommon causes
The downstream reader of the log stream closed
Piping the job to head, tee, or a truncating consumer that exits early closes the pipe. Continued winston writes to that stream fail with EPIPE.
A custom stream transport whose target closed
A Stream transport pointed at a socket or file handle that was closed keeps receiving writes, producing EPIPE on the next log line.
How to fix it
Handle stream errors on the transport
- Attach an error handler so an EPIPE on stdout does not crash the process.
- Avoid piping CI output to a consumer that exits before the job.
- Prefer file transports over fragile pipes for high-volume logs.
process.stdout.on('error', (err) => {
if (err.code === 'EPIPE') return; // downstream closed; ignore
throw err;
});Log to a file transport in CI
Write to a file instead of a pipe that a downstream tool may close early.
new winston.transports.File({ filename: 'ci.log' })How to prevent it
- Attach an error handler to stdout / stream transports.
- Avoid piping job output to consumers that exit early.
- Use a file transport for heavy logging in CI.