Investigation of Nginx 502 Errors Caused by PHP‑FPM Warning Triggering a FastCGI Buffer Defect
This article analyses why seemingly normal PHP‑FPM requests can cause Nginx to return 502 errors, revealing a FastCGI fastcgi_buffer_size bug triggered by warning output, describing the reproduction steps, detailed packet analysis, the underlying protocol mechanics, and practical recommendations for developers and operators.
Abstract
Although a PHP‑FPM request appears normal, Nginx may return a 502 error because PHP warning output triggers a defect in Nginx's FastCGI buffer handling. The article details the reproduction method, experimental results, and concludes with improvement suggestions.
Phenomenon Overview
In an LNMP stack, Nginx occasionally logs a 502 error with a "too big header" message. The PHP script’s header size never exceeds 1 KB, while the FastCGI buffer is at least 4 KB, so the error is not caused by an oversized header alone.
When the PHP script also emits a warning, the 502 does not correlate directly with warning length; a more complex pattern exists.
Finding the Pattern
Using the warning length as a clue, an experiment was conducted to correlate warning length with HTTP status. The environment: Windows 10 x64, PHP 7.0.12, Nginx 1.11.5 (same as the master branch). The FastCGI buffer was deliberately set to 1 KB.
fastcgi_buffer_size 1k;A PHP script receives a GET parameter len to control warning length, outputting the warning via error_log :
<?php
ob_flush();
flush();
$msg = str_pad("e", $_GET["len"], "e");
error_log($msg);
?>A shell script iterates len from 0 to 4000, fetching the HTTP status with curl :
#!/bin/bash
for((i=0;i<=4000;i++)); do
s=$(curl -I -m 10 -o /dev/null -s -w %{{http_code}} "1.1.1.1/index.php?len=$i")
printf "len=%4s status=%3s\n" $i $s
doneThe result shows alternating 200 and 502 statuses in blocks of 79 consecutive 502 responses, with each block spaced exactly 1024 bytes apart – the size of the FastCGI buffer.
FastCGI Communication Protocol
The FastCGI protocol wraps all data in FCGI_Record structures. Two special C‑style simplifications are used: adjacent members ending with B1 and B0 form a 16‑bit integer, and structs may contain variable‑length arrays.
typedef struct {
unsigned char version;
unsigned char type;
unsigned char requestIdB1;
unsigned char requestIdB0;
unsigned char contentLengthB1;
unsigned char contentLengthB0;
unsigned char paddingLength;
unsigned char reserved;
unsigned char contentData[contentLength];
unsigned char paddingData[paddingLength];
} FCGI_Record;Key fields: version (FastCGI version, currently 1), type (record type, e.g., BEGIN_REQUEST, STDIN, STDOUT, STDERR, END_REQUEST), contentLength (size of contentData ), and paddingLength (alignment bytes).
Root Cause of "too big header"
When parsing the FastCGI stream, Nginx’s state machine returns NGX_AGAIN after consuming the configured 1 KB buffer without having confirmed the complete header. Because the buffer is full, Nginx aborts with a 502 and logs "too big header".
Packet Analysis (len=936)
For len=936 , the TCP dump shows the first FCGI_Record (type FCGI_STDERR ) starting at offset 0x0020, with contentLength=0x03a9 and paddingLength=0x07 . The second record (type FCGI_STDOUT ) starts at 0x03e0, with contentLength=0x0044 . The header data ends with the sequence 0d 0a 0d 0a at byte positions 1025‑1029, exceeding the 1 KB buffer.
Why the 502 Distribution Is Not Fully Continuous
When the stderr buffer fills before any stdout data arrives, Nginx clears the buffer and continues receiving, creating a 1024‑byte interval trigger. This explains why 502 responses appear in blocks spaced by 1024 bytes.
Conclusion
Because stderr and stdout share the same buffer with equal priority, a sufficiently long warning can displace stdout data, causing the "too big header" log and a 502 response even though the FastCGI application may have processed the request successfully. Unlike genuine FastCGI process exhaustion, this 502 occurs after request handling, so retry logic must consider idempotency.
To mitigate the issue, increase the priority of stdout data or allocate separate buffers for stderr and stdout. Adjusting fastcgi_buffer_size can alleviate the problem for short warnings, but the proper fix is to eliminate all warnings in production code.
PHP Development Recommendations
Do not ignore warnings; they can become errors under certain buffer conditions. Ensure all warnings are resolved before release.
If warnings are unavoidable, increase fastcgi_buffer_size to accommodate them, but be aware that large warning bursts may still cause intermittent 502s.
Redirect PHP error output to a file instead of STDOUT/STDERR: display_errors = Off; log_errors = On; error_log = "path/to/log";
Study the FastCGI specification, PHP‑FPM source, and Nginx FastCGI module code for deeper understanding.
References
FastCGI Specification by Mark R. Brown
Nginx一次奇怪的502报错探究 by 浮生(企业代号名) @ 贝壳产品技术
Beike Product & Technology
As Beike's official product and technology account, we are committed to building a platform for sharing Beike's product and technology insights, targeting internet/O2O developers and product professionals. We share high-quality original articles, tech salon events, and recruitment information weekly. Welcome to follow us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.