Closing a TCP socket with unread data pending triggers a RST, causing intermittent ECONNRESET between localhost services like nginx and gunicorn.
Key Takeaways
Reproducer: server forks, dumps 600,000 bytes, closes socket; client sending data first (–spam) before reading causes ECONNRESET via TCP RST.
tcpdump and strace confirm RST originates from the server after close(), not from a crash or buffer overflow.
Root cause hypothesis: calling close() with unread incoming data on the socket causes the kernel to fire a RST instead of a clean FIN.
Real-world case: nginx splits HTTP requests across two writev() calls; gunicorn sometimes reads only the first 392-byte chunk (headers), ignores 22-byte body, then closes, triggering RST.
Workaround: force the Python/Flask app to read the full request body before responding; note this can open DoS risk for large POST bodies without nginx client_max_body_size limits.
Hacker News Comment Review
Commenters treat the close()-with-unread-data-causes-RST behavior as settled, well-documented TCP behavior for 30+ years, not a kernel quirk or bug.
The Apache httpd perf-tuning docs section on Lingering Close is flagged as essential reading for anyone building HTTP servers that need to avoid this pattern.