BrokenPipeError: [Errno 32] Broken pipe (tested)
BrokenPipeError: [Errno 32] Broken pipe means Python wrote to a pipe or socket after the reader went away. We measured the three common places it comes from on Python 3.13.5, and which fixes leave no traceback behind.
1. Piping into head: the classic cause
for i in range(100000):
print(i)
Piped into head:
$ python3 b1.py | head -n 2; echo "exit=${PIPESTATUS[0]}"
0
1
Traceback (most recent call last):
File "/tmp/bp/b1.py", line 2, in <module>
print(i)
~~~~~^^^
BrokenPipeError: [Errno 32] Broken pipe
exit=1
Measured on Python 3.13.5 (Linux): head -n 2 reads two lines and exits. The next time Python flushes stdout, the pipe has no reader, the write fails with EPIPE, and Python raises BrokenPipeError: [Errno 32] Broken pipe. Python ignores SIGPIPE at startup, so you get an exception where cat or grep would just stop. The same happens with | less (quit early), | grep -m1, and | python -c "input()".
2. Fix: catch it and exit quietly (cross-platform)
import os, sys
try:
for i in range(100000):
print(i)
sys.stdout.flush()
except BrokenPipeError:
# Python flushes stdout again at exit; point it at devnull so that doesn't fail too
devnull = os.open(os.devnull, os.O_WRONLY)
os.dup2(devnull, sys.stdout.fileno())
sys.exit(1)
Piped into head:
$ python3 b2.py | head -n 2; echo "exit=${PIPESTATUS[0]}"
0
1
exit=1
This is the pattern the Python docs recommend (the signal module's note on SIGPIPE). The dup2 to devnull is there because Python flushes stdout once more at exit; if output is still buffered, that flush hits the same broken pipe and prints Exception ignored ... BrokenPipeError. In our run, a version without the dup2 happened to exit cleanly too, but that depends on what is left in the buffer, so keep it.
3. Fix: restore default SIGPIPE (Unix CLI tools)
import signal
signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Unix only: die quietly like cat/grep do
for i in range(100000):
print(i)
Piped into head:
$ python3 b3.py | head -n 2; echo "exit=${PIPESTATUS[0]}"
0
1
exit=141
Measured: no traceback, and the exit status is 141 (128 + signal 13), the same as other Unix tools killed by SIGPIPE. Only do this in a command-line program: in a server, a client hanging up on a socket would kill the whole process instead of raising an exception you can handle. signal.SIGPIPE doesn't exist on Windows.
4. Sockets: the other side closed the connection
import socket
a, b = socket.socketpair()
b.close() # the other side hung up
try:
a.sendall(b"x" * 100)
except BrokenPipeError as e:
print(type(e).__name__, e)
try:
a.sendall(b"x" * 100)
except OSError as e:
print("again:", type(e).__name__, e.errno)
Output:
BrokenPipeError [Errno 32] Broken pipe
again: BrokenPipeError 32
Measured: writing to a socket whose peer has closed raises BrokenPipeError (on a TCP connection the first write may succeed and the second fail, or you may get ConnectionResetError: [Errno 104] instead). In a web server this usually means the browser or client gave up (navigated away, timed out); log it at debug level rather than treating it as a bug. For clients, reconnect and retry if the request is safe to repeat.
5. subprocess: writing to a child that already exited
import subprocess
p = subprocess.Popen(["head", "-c", "1"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL)
p.stdin.write(b"a")
p.stdin.flush()
p.wait() # head has exited
try:
p.stdin.write(b"b" * 100000)
p.stdin.flush()
except BrokenPipeError as e:
print("write after child exit:", type(e).__name__, e)
p2 = subprocess.Popen(["head", "-c", "1"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL)
out, err = p2.communicate(b"b" * 1000000) # communicate() ignores EPIPE
print("communicate returncode:", p2.returncode)
Output:
write after child exit: BrokenPipeError [Errno 32] Broken pipe
communicate returncode: 0
Measured: writing to p.stdin after the child exited raises BrokenPipeError; communicate() with the same data doesn't, because it ignores EPIPE when sending input. Prefer communicate(input) or subprocess.run(..., input=...) over writing to stdin yourself.
Frequently asked questions
What does BrokenPipeError: [Errno 32] Broken pipe mean?
Python wrote to a pipe or socket with no reader left. We measured it from print() piped into head -n 2, a socketpair whose peer was closed, and a subprocess stdin after the child exited.
Why does python script.py | head raise BrokenPipeError?
head exits after its lines, and Python ignores SIGPIPE, so the next stdout flush raises instead of quietly ending the process. Catch it and dup2 devnull onto stdout, or restore SIG_DFL for SIGPIPE in CLI tools.
How do I suppress Exception ignored BrokenPipeError at exit?
After catching BrokenPipeError, point stdout at os.devnull with os.dup2 before exiting, so Python's final flush of any still-buffered output has somewhere to go. We measured this pattern exits with no traceback and status 1.
Is it safe to set signal.SIGPIPE to SIG_DFL?
In a command-line tool, yes (we measured exit status 141 and no traceback). In a server, no: a client disconnecting would kill the process. It's also unavailable on Windows.
Why does subprocess raise BrokenPipeError?
You wrote to p.stdin after the child exited. We measured communicate() with the same input returning normally, so use communicate() or subprocess.run(input=...).
Written with AI assistance. Measured on 2026-10-09 with Python 3.13.5 on Linux: print() piped into head with no fix, the catch + dup2 fix and SIGPIPE SIG_DFL, a socketpair with a closed peer, and subprocess stdin after the child exited. Every block was run verbatim and its output pasted from that run. Windows and macOS were not tested. PlainHeaders is our extension; everything else here is built-in Python.