Skip to content
RU

write EPIPE / Broken Pipe: Why Writes Fail After the Peer Closes

What it means: Your process wrote data into a socket or pipe whose reading side was already closed.

  1. Find what closed the other end
  2. Check upload size limits and timeouts
  3. Stop writing after close or error
  4. Handle EPIPE on stdout pipes

Test your URL now

Requests the address and shows the status code and what the server sends back.

What EPIPE means

EPIPE («Broken pipe», errno 32 on Linux) is returned by write(2) when the descriptor «is connected to a pipe or socket whose reading end is closed». The same page notes that the writing process also receives a SIGPIPE signal, which kills it by default; the error code is only seen by programs that catch, block or ignore that signal. Node.js ignores SIGPIPE by default (process docs), so it surfaces as an error event instead:

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

The Node.js docs describe it as «A write on a pipe, socket, or FIFO for which there is no process to read the data. Commonly encountered at the net and http layers, indicative that the remote side of the stream being written to has been closed.» Python raises BrokenPipeError: [Errno 32] Broken pipe; curl reports a send failure (exit code 55, «Failed sending network data»).

EPIPE and ECONNRESET are two views of the same event. If the peer's reset arrives before your next read, you get ECONNRESET; if your next operation is a write to the already-closed socket, you get EPIPE. Which one appears is a matter of timing.

Causes

SituationWho closed the connectionFix
Large upload to an HTTP serverThe server rejected the body (for example 413) and closed while the client kept sendingRaise the server limit or upload in parts
Writing a long response to a slow or gone clientThe browser navigated away or the client timed outStop writing on 'close'; treat as normal disconnect
Reused keep-alive or database connectionThe server dropped the idle connectionShorter client idle timeout; validate pooled connections
node script.js | headhead exited after reading enough linesHandle EPIPE on process.stdout
Child process stdinThe child exited before reading all inputCheck the child's exit code; handle the stdin error
Proxy timeout on a long requestnginx or a load balancer closed after its timeoutAlign proxy and app timeouts; stream progress

EPIPE in an HTTP server or client

On the client side, the most common trigger is an upload the server stops reading. The server answers early with an error status and closes; the client is still pushing the body and hits EPIPE before it ever reads that status. Check the server's body limit first, for nginx client_max_body_size, and read the server log for the same timestamp. A response you never saw because of EPIPE is often a plain 413.

On the server side, EPIPE while writing a response usually means the client left: closed the tab, hit a timeout, or a proxy gave up first. That is normal traffic, not a bug, but an unhandled 'error' event on the stream still crashes a Node.js process. Listen for it and stop producing data:

res.on('close', () => { stream.destroy(); });
stream.on('error', (err) => {
  if (err.code === 'EPIPE' || err.code === 'ECONNRESET') return; // client went away
  console.error(err);
});
stream.pipe(res);

When this happens at a fixed duration on long requests, a proxy in front is closing the connection; see upstream prematurely closed connection for the nginx side.

EPIPE on stdout in CLI scripts

Command-line tools hit EPIPE when their output is piped into a program that stops reading early. node list.js | head -n 5 works until head exits after line five; the next write to stdout fails. Shell tools written in C are simply killed by SIGPIPE, which is why yes | head exits quietly. In Node.js, end the process cleanly instead of printing a stack trace:

process.stdout.on('error', (err) => {
  if (err.code === 'EPIPE') process.exit(0);
  throw err;
});

How to fix it

  1. Identify the stream. The stack trace tells you whether the write was to an HTTP request body, a response, a database socket or stdout.
  2. For uploads, read the server's verdict. Send the same request with curl and watch for an early response:
    curl -v -T big.bin https://api.example.com/upload
    # < HTTP/1.1 413 Request Entity Too Large
  3. Check idle and request timeouts on every hop (load balancer, nginx proxy_read_timeout, the app server) and keep the upstream one longer.
  4. Validate pooled connections before use, or lower the pool's idle timeout below the server's.
  5. Handle the error event on every stream you write to, and stop writing once 'close' has fired.

How to confirm the fix

curl -sS -o /dev/null -w '%{http_code}\n' -T big.bin https://api.example.com/upload
# 201

Then check application logs over a normal day: EPIPE from clients that disconnect will still occur occasionally and should be logged at debug level, not as crashes. The HTTP status checker shows the status code and headers a URL returns.

Related errors

60+ Status CodesComplete HTTP status code reference
Search by CodeQuick search for 200, 301, 404, 500
Categories 1xx–5xxInformational, success, redirects, errors
Examples & CausesWhen it occurs and how to fix it

Why teams trust us

60+
status codes
1xx-5xx
all categories
SEO
ranking impact
Free
online reference

How to use the reference

1

Enter code or keyword

2

Find description and causes

3

Apply recommendations

HTTP Status Codes Reference

HTTP status codes are three-digit numbers that the server returns for every request. They tell the browser and search crawlers what happened: success, redirect, or error.

Quick Search

Enter a code or keyword — instant result with description.

All Categories

1xx Informational, 2xx Success, 3xx Redirect, 4xx Client Error, 5xx Server Error.

Causes & Fixes

For each code: typical causes and concrete steps to resolve.

SEO Impact

How each code affects indexing and link juice transfer in Google.

Who uses this

Developers

choosing correct status

SEO

redirect optimization

DevOps

5xx error diagnostics

Marketers

landing page check

Common Mistakes

Confusing 301 and 302301 is permanent (passes SEO equity), 302 is temporary (does not).
Returning 200 on error"Soft 404s" — a 404 page with status 200 — confuse search engines and stay indexed.
Ignoring 5xx errors500, 503 are server failures. Prolonged episodes remove pages from the index.
Redirect chainsA→B→C instead of A→C slows loading and dilutes SEO equity. Simplify chains.

Best Practices

Use 301 for permanent redirectsThis passes 90–99% of link equity to the new URL.
Return 404 for missing pagesDon't mask 404 as 200 — it hurts SEO and UX.
Monitor 5xx in real timeSet up an HTTP monitor that alerts on 5xx.
Use 410 instead of 404410 Gone means "page permanently removed" — Google de-indexes faster.

Monitor HTTP statuses automatically

HTTP monitor alerts when response code changes or 5xx appears.

Sign up free

Learn more

Sources

Frequently Asked Questions

What is the difference between EPIPE and ECONNRESET?

Both mean the peer closed the connection. You get EPIPE when your next action is a write and ECONNRESET when the reset is noticed on a read.

Why does node script.js | head print write EPIPE?

head exits after reading its lines, so the next write to stdout goes to a closed pipe. Handle the EPIPE error on process.stdout and exit quietly.

Why does a large upload fail with EPIPE?

The server rejected the body, often with 413, and closed the connection while the client was still sending. Raise the server's body size limit.

Should EPIPE crash my server?

No. It usually means a client disconnected. Handle the stream error event, stop writing and log it at a low level.

Try the live tool that powered this guide

Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.