How to Fix BrokenPipeError: [Errno 32] Broken Pipe in Python

BrokenPipeError: [Errno 32] Broken pipe means Python tried to write to a pipe or socket whose receiving end was closed or could no longer accept writes. The fix is to find out why the reader stopped, then either restore the connection or stop writing when that closure is expected. Start with the failing operation in the traceback, not a blanket exception handler.

Use this table to match the error to its likely cause.

Where the Error Appears Likely Cause Appropriate Fix
print() or sys.stdout.flush() in a shell pipeline The downstream command stopped reading Handle early closure at the command-line output boundary
A write to a subprocess’s standard input The child exited, rejected its input, or closed its input stream Inspect the child’s exit status and error output; correct its input or lifecycle
An HTTP response write The browser, client, or proxy disconnected End that response cleanly; investigate repeated unexpected disconnects
socket.send() or socket.sendall() The connection was closed, shut down, or reused after becoming stale Discard the failed connection and reconnect only when retrying is safe
Multiprocessing or worker communication The receiving worker exited or crashed Find the worker’s original failure before restarting the work

What BrokenPipeError Means

A pipe connects a writer to a reader. A socket provides a communication endpoint, often between processes on different machines. If the receiving side disappears, a later write can fail.

On Linux and macOS, error number 32 normally corresponds to EPIPE. In Python, BrokenPipeError is a subclass of ConnectionError, which is itself an OSError. If you need to compare operating-system error codes, use errno.EPIPE rather than hard-coding the number.

Common triggers include:

  • A command intentionally reading only the beginning of another command’s output.
  • A child process exiting before its parent finishes sending input.
  • A browser canceling a download or navigating away.
  • A server closing an idle connection.
  • Application code writing after shutting down a socket’s write side.

A broken pipe identifies the failed write, not necessarily the failure that caused the receiver to disappear.

Buffering can also delay the exception. A print() call may put text into a Python buffer successfully, while the actual failure appears during flush() or interpreter shutdown.

Related errors are not interchangeable. A stream socket returning empty bytes from a receive operation indicates end-of-stream; ConnectionResetError indicates a reset. Depending on timing and protocol behavior, a disconnected peer may produce either a broken-pipe error or a connection-reset error.

How to Fix BrokenPipeError in Python

Identify the failed write, determine why the receiver closed, and repair the connection or process lifecycle before validating the result.

Step 1: Identify the Failing Write

  1. Read the traceback from the bottom upward. Find the write, send, or flush operation that failed, then locate the nearest frame belonging to your application.
  2. Identify the receiving process or connection. Determine whether Python was writing to terminal output, a subprocess, a client socket, or an internal worker.
  3. Check whether the exception occurred during normal work or cleanup.

A traceback ending inside a standard-library function does not automatically indicate a Python bug. For example, an HTTP response may pass through several library layers before the socket write fails. Your request handler and the client’s behavior are still the useful starting points.

If the message appears as “Exception ignored in” during shutdown, buffered output may be getting flushed during shutdown. Catching an exception around one earlier print() call will not cover that later flush.

Keep the complete traceback and the messages immediately before it. The final exception line alone rarely identifies the root cause.

Step 2: Find Out Why the Receiver Closed

  1. Reproduce the problem with the simplest version of the original operation. For a command-line program, compare direct output with piped output. For a service, use a single request before introducing concurrent traffic.
  2. Inspect the receiver’s logs, exit status, or cancellation behavior.
  3. Correlate the failure with shutdowns, deployments, worker crashes, resource limits, or configured connection timeouts.

For a subprocess, its standard error often contains the useful failure: invalid arguments, malformed input, a missing file, or an application exception. The parent’s broken pipe may simply be the next event.

For a containerized worker, check whether it was terminated or restarted. An out-of-memory termination can leave the sending process reporting a communication error even though the original problem was resource exhaustion.

For a remote service, check both ends of the connection when possible. A network intermediary can close a connection even when neither application deliberately does so.

Make this distinction before changing code:

  • Expected closure: The receiver intentionally stops early, such as a command that needs only the first few output lines.
  • Unexpected closure: The receiver should have continued, but crashed, timed out, or rejected the operation.

The first needs controlled shutdown. The second needs its underlying failure repaired.

Step 3: Repair the Connection or Process Lifecycle

  1. Restore a receiver that failed unexpectedly. Correct the child-process error, service crash, invalid request, or deployment interruption identified in the logs.
  2. Remove writes that occur after your application has closed or shut down the communication channel.
  3. Apply the relevant lifecycle repair below, then repeat the operation and validate its result.

Once a write fails with a broken pipe, discard that connection rather than repeatedly sending through it. Establish a fresh connection through the application’s normal connection setup, including any authentication or protocol handshake.

Do not automatically replay every failed request. Python’s sendall() can raise after sending part of the data, and the exception does not tell you how much the application on the other end processed.

A failed write does not prove that the remote operation failed.

Retry automatically only when the operation is safe to repeat, or when the protocol provides a deduplication mechanism such as an idempotency key. Otherwise, check the operation’s status before submitting it again. Finish by validating the expected application response, not merely by checking that a new socket opened.

For bounded input and output, prefer subprocess.run() over manually coordinating writes, flushes, reads, and process exit. This complete example sends input to a child Python process and captures its response:

import subprocess
import sys
result = subprocess.run(
    [
        sys.executable,
        "-c",
        "import sys; "
        "sys.stdout.buffer.write(sys.stdin.buffer.read().upper())",
    ],
    input=b"example input\n",
    capture_output=True,
    check=True,
)
print(result.stdout.decode(), end="")

The expected output is EXAMPLE INPUT followed by a newline. Replace the demonstration child with your actual program, preserving the arguments it requires.

With check=True, an unsuccessful child exit raises subprocess.CalledProcessError; inspect that exception’s returncode and captured stderr. For an existing Popen workflow, communicate() coordinates input, output, and process completion.

These APIs are not proof that the child consumed every byte. Validate the child’s output or application-level acknowledgment as well. Also, captured output is buffered in memory, so unbounded streams need a streaming design that drains output while managing child exit.

Coordinate shutdown and recovery for shared connections and worker queues.

Give connection shutdown a clear owner. One thread or task must not close a channel while another still expects to write through it.

After repairing a worker failure, restart the affected worker or channel and resubmit only work whose completion status is known. Verify that the worker completes the task and that the sender receives its expected result.

Step 4: Handle Expected Early Closure Cleanly

  1. Catch disconnect errors at the narrow boundary where an early exit is acceptable.
  2. Stop producing data for the closed destination.
  3. Release the affected resources and return an appropriate status without hiding unrelated failures.

For a standalone Python command writing to standard output on Linux or macOS, handle both ordinary writes and the final explicit flush.

import os
import sys
def main():
    for number in range(100_000):
        print(number)
    # Detect a buffered write failure inside the try block.
    sys.stdout.flush()
if __name__ == "__main__":
    try:
        main()
    except BrokenPipeError:
        # Prevent another broken-pipe error during shutdown flushing.
        devnull_fd = os.open(os.devnull, os.O_WRONLY)
        try:
            os.dup2(devnull_fd, sys.stdout.fileno())
        finally:
            os.close(devnull_fd)
        sys.exit(1)

This pattern assumes a normal command-line standard-output stream with a file descriptor. It is not intended for notebook output or arbitrary replacement stream objects.

Test an early-closing reader:

python broken_pipe_demo.py | head -n 5

Check whether the pipeline displays the requested lines without a Python traceback. The producer deliberately exits with status 1 in this example; a shell configured to report upstream pipeline failures may therefore mark the pipeline unsuccessful. A CLI that defines intentional truncation as success can choose a successful exit status instead.

Then test a reader that accepts the complete output:

python broken_pipe_demo.py > output.txt

Confirm that the file contains the complete sequence and the program exits normally. Keep this handler specific to a stdout-producing command; wrapping an entire network application in it could misclassify an unrelated broken socket as harmless output truncation.

Do not use flush=True as a broken-pipe repair. It changes when data is written, not whether a reader exists. Likewise, resetting SIGPIPE to its operating-system default is not a general Python fix: it can terminate the process on a broken socket rather than letting application code handle the exception.

If a client is allowed to disconnect, handle BrokenPipeError and, where appropriate, ConnectionResetError around the response-writing boundary. Stop generating that response and release any associated files, generators, or upstream requests.

Do not continue writing to the connection from inside the exception handler. Avoid catching every Exception, because that would also conceal application errors unrelated to client cancellation.

Test this handling by canceling a request, confirming that its resources are released, and then making another request. The server should remain available, and the next response should complete successfully.

Broken Pipes in Local Web Servers

A browser can abandon an HTTP request during navigation, refresh, or cancellation. If the server continues copying a file or streaming a response afterward, the resulting traceback may end in a socket write.

That does not necessarily mean the server process crashed. Check whether it still accepts requests and whether the browser actually received the content it needed. Repeated failures during an ordinary page load deserve investigation, especially if scripts, data files, or API responses remain incomplete.

For local dashboards, also distinguish a connection problem from an interpreter or environment mismatch.

If the legacy SimpleHTTPServer module works while the intended server does not, that invocation likely uses Python 2 rather than Python 3. Confirm the interpreter behind the actual server command.

For a CloudMapper checkout that uses Pipenv, enter its environment from the project root if it is not already active:

pipenv shell

Then check the Python version:

python --version

Check the executable being launched:

python -c "import sys; print(sys.executable)"

Compare those results with the project’s environment and the interpreter paths in the failing traceback. Do not downgrade to an obsolete interpreter merely because a legacy server module starts.

When CloudMapper’s webserver command raises BrokenPipeError, a local workaround is to serve its generated files directly from the project’s web directory, using the command provided in the CloudMapper project discussion.

From the project root, change directories:

cd web

Start the server:

python -m http.server --bind 127.0.0.1

The loopback binding limits access to the local machine. Open http://127.0.0.1:8000 and check that the dashboard and its data requests load successfully.

This is a local serving workaround, not a guarantee that every broken pipe has been resolved. If requests still fail, inspect the browser’s failed requests and the server traceback. Python’s simple HTTP server is suitable for this local check, not as a replacement for a production application server. Stop it with Ctrl+C when finished.

How to Confirm the Fix and Prevent Recurrence

Use both a successful-operation test and an interrupted-operation test:

  • Normal completion: The intended output, response, or job result arrives intact.
  • Expected interruption: Canceling a client or closing a reader stops the affected work without crashing unrelated work.
  • Resource cleanup: Child processes finish or are reaped, sockets close, and canceled streams release their resources.
  • Useful diagnostics: Unexpected disconnects retain the request context, receiver error, or child exit status needed for investigation.
  • Safe retries: Repeated submissions cannot silently duplicate a completed operation.

Do not judge success solely by the disappearance of the traceback. A broad exception handler can make logs quiet while dropping output or abandoning work.

For prevention, make connection ownership explicit, validate pooled connections through the client library’s supported lifecycle, and align request deadlines with the application’s intended behavior. Increasing every timeout or buffer size without identifying the closing endpoint is unlikely to produce a reliable fix.

If the problem remains, collect a minimal reproducer, the full traceback, and the receiver’s logs or exit status. That combination is far more actionable than the broken-pipe message alone.

Frequently Asked Questions

What Causes a Broken Pipe With a Google Cloud Load Balancer?

A broken pipe in an application behind a Google Cloud load balancer means a connection became unwritable; the message alone does not identify which endpoint closed it. Possible causes include client cancellation, backend shutdown, or a timeout on the relevant connection leg. Correlate application logs with load-balancer request logs and the configuration for the specific load-balancer type before changing timeout settings.

Does a Broken Pipe Socket Exception in C# Mean the Same Thing?

Yes, it generally indicates the same underlying communication problem: an application attempted to write through a connection that could no longer accept data. In .NET, the failure may appear as a SocketException or as an IOException containing a socket exception, depending on the API and operating system. Inspect SocketErrorCode and any inner exception rather than assuming Python’s numeric error mapping applies unchanged.

Why Does RHEL Registration Fail With a Broken Pipe?

A broken pipe during RHEL registration indicates an interrupted communication path, not necessarily an invalid subscription. Check the registration client’s diagnostic output, the configured proxy, name resolution, and connectivity to the intended registration endpoint. Correct the reported connection or service failure without disabling certificate validation, then retry registration and confirm the system’s registration status.