What do I do if the Cannot modify header information - headers already sent by (output started at ... message is reported when an HTTP trigger is used in a PHP environment?
This error occurs when your PHP code attempts to send an HTTP header after output has already started. In the Function Compute (FC) PHP runtime, the fix depends on which HTTP trigger mode your function uses.
For additional context, see the community article on this error.
HTTP trigger modes
The PHP runtime HTTP trigger supports two modes:
Without `fcPhpCgiProxy`: The function handler returns a
Responseobject directly. This is the recommended mode for API-style functions.With `fcPhpCgiProxy`: The function acts as an Apache/Nginx location block, forwarding requests to php-fpm. This mode supports traditional PHP web projects where
header(),setcookie(), and similar functions work as expected.
Root cause
When PHP produces its first output (echo, print, or any whitespace outside PHP tags), it flushes all collected headers. After that point, any call to a function that modifies HTTP headers raises:
Cannot modify header information - headers already sent by (output started at ...)The following PHP functions trigger this error when running without fcPhpCgiProxy:
header()andheader_remove()setcookie()andsetrawcookie()session_start()andsession_regenerate_id()
Solution
Without fcPhpCgiProxy
Pass all response headers through the Response object constructor. Do not call header(), setcookie(), or similar functions separately.
<?php
use RingCentral\Psr7\Response;
function handler($request, $context): Response
{
return new Response(
200,
array(
"custom_header1" => "v1",
"custom_header2" => ["v2", "v3"],
"Set-Cookie" => urlencode("test php") . '=' . urlencode('test;more')
),
"hello world"
);
}With fcPhpCgiProxy
The fcPhpCgiProxy mode runs PHP files through php-fpm, so header(), setcookie(), and session functions work normally. The entry function forwards the request to the proxy, and the target PHP file handles headers in the standard PHP way.
Entry function file:
<?php
function http_fc_func_cgi($request, $context): Response
{
$proxy = $GLOBALS['fcPhpCgiProxy'];
return $proxy->requestPhpCgi(
$request,
__DIR__ . '/www',
"index.php",
['SERVER_NAME' => 'example.com']
);
}Target PHP file (inside www/):
<?php
http_response_code(200);
header('Content-Type: text/html');
echo "<html><body>Hello world</body></html>";
?>Legacy code with ob_start()
If existing PHP code mixes header() calls with output and cannot be easily refactored, use output buffering as a temporary workaround. Call ob_start() at the start of your script to buffer all output, which allows header() calls to succeed even after echo statements.
<?php
ob_start();
echo "some output";
header('X-Custom-Header: value'); // works because output is buffered
$output = ob_get_clean();Note: Output buffering is a workaround for legacy code. For new functions, use theResponseobject pattern (withoutfcPhpCgiProxy) or migrate tofcPhpCgiProxymode.
Which mode should I use?
| Scenario | Recommended mode |
|---|---|
| API functions returning JSON, XML, or simple responses | Without fcPhpCgiProxy — use the Response object |
| Web applications or projects migrated from Apache/Nginx | With fcPhpCgiProxy — standard PHP header functions work as expected |