BrokenPipeError — Broken Pipe Fix
A BrokenPipeError is raised when you try to write to a pipe, socket, or stream whose reading end has been closed. It’s a subclass of ConnectionError (which is a subclass of OSError). On Unix systems, this often manifests as SIGPIPE.
Description
When one end of a pipe or socket closes the connection and the other end continues writing, the operating system sends a SIGPIPE signal. Python raises BrokenPipeError on Unix systems when this occurs. On Windows, the behavior is similar but without the SIGPIPE signal.
Common scenarios:
- Client disconnects mid-response — web server writes to a client that closed the browser.
- Piped commands fail —
headcloses its stdin, causinggrepto getBrokenPipeError. - Socket peer closes connection — writing to a socket after the remote end called
close(). - Subprocess closes stdin — parent writes to a subprocess that has already exited.
Common Causes
import socket
# Cause 1: Writing to a closed socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("example.com", 80))
sock.close()
sock.send(b"data") # BrokenPipeError
# Cause 2: Piped command closes stdin
import subprocess
p = subprocess.Popen(["grep", "pattern"], stdin=subprocess.PIPE)
p.stdin.write(b"some data\n")
p.stdin.close() # BrokenPipeError if grep exits early
# Cause 3: Client disconnects from server
server_sock, addr = server.accept()
data = server_sock.recv(1024)
client_sock.close() # Client disconnects
server_sock.send(b"response") # BrokenPipeError
# Cause 4: Writing to a closed pipe
import os
r, w = os.pipe()
os.close(r) # Close read end
os.write(w, b"data") # BrokenPipeError
Solutions
Fix 1: Handle BrokenPipeError with try/except
import socket
# Wrong — assumes connection stays open
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("example.com", 80))
sock.send(b"GET / HTTP/1.0\r\n\r\n")
response = sock.recv(4096)
# Correct — handle broken pipe
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("example.com", 80))
try:
sock.send(b"GET / HTTP/1.0\r\n\r\n")
response = sock.recv(4096)
except BrokenPipeError:
print("Connection was closed by the remote end")
finally:
sock.close()
Fix 2: Ignore SIGPIPE on Unix systems
import signal
import socket
# Wrong — SIGPIPE kills the process on some systems
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
# Correct — ignore SIGPIPE so Python raises BrokenPipeError instead
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect(("example.com", 80))
sock.send(b"data")
except BrokenPipeError:
print("Pipe broken, handled gracefully")
Fix 3: Check socket state before writing
import socket
import select
# Wrong — blindly writes to socket
sock.send(b"data")
# Correct — check if socket is still writable
ready, _, _ = select.select([], [sock], [], 1.0)
if ready:
try:
sock.send(b"data")
except BrokenPipeError:
print("Connection broken")
Fix 4: Handle BrokenPipeError in web servers
from http.server import HTTPServer, BaseHTTPRequestHandler
# Wrong — crashes when client disconnects
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"Hello, World!") # BrokenPipeError if client leaves
# Correct — handle BrokenPipeError
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
try:
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"Hello, World!")
except BrokenPipeError:
pass # Client disconnected, ignore
server = HTTPServer(("localhost", 8080), Handler)
server.serve_forever()
Fix 5: Use context managers for pipe safety
import subprocess
import sys
# Wrong — pipe may break
p = subprocess.Popen(["head", "-5"], stdin=subprocess.PIPE)
p.stdin.write(b"line1\nline2\n")
p.stdin.close()
# Correct — handle BrokenPipeError in piped commands
try:
p = subprocess.Popen(["head", "-5"], stdin=subprocess.PIPE)
p.stdin.write(b"line1\nline2\n")
p.stdin.close()
except BrokenPipeError:
# Reset SIGPIPE to default behavior
import signal
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
Related Errors
- ConnectionResetError — connection reset by remote end.
- ConnectionAbortedError — connection aborted by local host.
- ConnectionError — base class for connection errors.
Comments