Error: write EPIPE
Node.js · updated 2026-11-03
Emitted as an 'error' event on a stream or socket when you write after the reader went away: a client that disconnected mid-response, a child process that exited, or stdout piped into a command like head that stopped reading. Without an error listener it crashes the process.
node:events:497
throw er; // Unhandled 'error' event
^
Error: write EPIPE
at afterWriteDispatched (node:internal/stream_base_commons:161:15)
at writeGeneric (node:internal/stream_base_commons:152:3)
at Socket._writeGeneric (node:net:953:11)
at Socket._write (node:net:965:8) {
errno: -32,
code: 'EPIPE',
syscall: 'write'
}Quick fix
Add an 'error' listener to every stream and child process stdin you write to, and stop writing once the other side has closed. Use stream.pipeline() so errors and early closes on either end are handled together. For CLI output piped to head, exit quietly on EPIPE.
- Find which stream wrote: a response socket, child.stdin, or process.stdout.
- Attach an 'error' handler (or use stream.pipeline / stream/promises pipeline) so EPIPE does not crash the process.
- Check writable state before writing (socket.destroyed, res.writableEnded), and stop on close.
- For child processes, wait for them to be ready and handle their exit before writing more input.
- For CLIs, treat EPIPE on stdout as a normal end: process.stdout.on('error', (e) => e.code === 'EPIPE' && process.exit(0)).
import { pipeline } from 'node:stream/promises';
import { createReadStream } from 'node:fs';
app.get('/export', async (req, res) => {
try {
// pipeline handles a client disconnect (EPIPE / ERR_STREAM_PREMATURE_CLOSE) cleanly
await pipeline(createReadStream('/data/export.csv'), res);
} catch (err: any) {
if (err.code !== 'EPIPE' && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') throw err;
}
});Why it happens
The client disconnected mid-response
A user closing the tab, a load balancer timing out or a mobile network dropping during a large download closes the socket while the server is still writing.
A child process exited early
Writing to child.stdin after ffmpeg, a shell command or a worker has crashed or finished raises EPIPE on the next write.
Output piped to a command that stops reading
node script.js | head -5 closes the pipe after five lines; the script keeps writing to stdout and gets EPIPE.
Writing after end() or destroy()
Code paths that keep writing after the stream was ended by another branch (a timeout, an error handler) trip over a closed socket.
Other fixes
- Client disconnects are normal for downloads and streaming: log them at info level instead of reporting them as errors.
- Set server timeouts (keepAliveTimeout, headersTimeout) consistently with your load balancer to reduce mid-response closes.
Same error, other wording
- Error: write EPIPE at WriteWrap.onWriteComplete
- Error [ERR_STREAM_PREMATURE_CLOSE]: Premature close
- Error: This socket has been ended by the other party
Let your coding agent catch the next one
Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:
> Find the EPIPE errors in production, show me which stream or child process was being written each time, and add error handling or pipeline() so client disconnects stop crashing or alerting.
Related errors
- Error: read ECONNRESET
- Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
- [UnhandledPromiseRejection: This error originated either by throwing inside of an async...
References: Node.js errors: common system errors (EPIPE), Node.js: stream.pipeline