php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #50921 '200 OK' HTTP status despite PHP error
Submitted: 2010-02-03 04:23 UTC Modified: 2015-12-14 09:27 UTC
Votes:91
Avg. Score:4.3 ± 0.9
Reproduced:78 of 79 (98.7%)
Same Version:27 (34.6%)
Same OS:12 (15.4%)
From: phpbug at starurl dot com Assigned:
Status: Re-Opened Package: HTTP related
PHP Version: 5.2.12 OS: *
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2010-02-03 04:23 UTC] phpbug at starurl dot com
Description:
------------
My host runs PHP v5.2.12 (confirmed via phpversion) on IIS6 (Windows Server, unknown version). When a PHP error occurs (parse error, runtime error, etc), a "200 OK" HTTP status is returned, instead of the correct "500 Internal Server Error".

This is despite claims in the change history for v5.2.4 that this issue was fixed:  "Changed error handler to send HTTP 500 instead of blank page on PHP errors. (Dmitry, Andrei Nigmatulin)". This doesn't appear to be the case on IIS6 (monitored remotely via HTTP Spy).

Reproduce code:
---------------
<?
x = y;  // cause parse error
?>

Expected result:
----------------
Parse error mesage and "500 Internal Server Error" HTTP status code.

Actual result:
--------------
Parse error mesage and "200 OK" HTTP status code

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-02-03 10:06 UTC] jani@php.net
It does happen. It requires that:

1) display_errors = off
2) No headers have been sent yet by the time the error happens
3) Status is 200 at that time.

 [2010-02-03 18:01 UTC] phpbug at starurl dot com
Thank you for the swift response Jani.

I can confirm that the 500 status code works for the following (runtime error):

    <?
    ini_set('display_errors', 0); 
    $x = y();
    ?>

But fails for parse errors (because the "disply_errors" line doesn't get executed):

    <?
    ini_set('display_errors', 0); 
    x = y;
    ?>

Firstly, is this dependency really necessary? Just because we have 'display_errors' enabled doesn't mean we want fatal errors to go unlogged and unnoticed because a "200 OK" status is incorrectly returned.

Secondly, the majority of PHP developers out there use shared hosting, on which 'display_errors' is normally true and is impossible to change globally - are we saying they're stuck with incorrect HTTP status codes when parse errors occur?

The restriction that headers must not already have been sent is of course understandable as it is unavoidable. Not overriding an explicitly set HTTP status code also makes sense.

But why not set the status code as "500 Internal Server Error" when any fatal parse/runtime error occurs, regardless of the value of 'display_errors'? This would be consistent with the HTTP spec, which recommends a 5XX response if an error occurs, and is followed by just about every other web server language out there (e.g., ASP, .NET).

Many thanks,  BJ
 [2010-02-03 19:03 UTC] derick@php.net
The reason why display errors needs to be turned of, is because displayed errors generate output, and output causes the headers to be send out. I'm afraid we can't do much about this.
 [2010-03-12 08:37 UTC] anzenews at volja dot net
I am also having huge problems with this - haproxy health checks do not work reliably because of this bug. Please consider reopening it - it is not bogus.

PHP doesn't return HTTP error code, even if display_errors is set to 0. One example:
<?
  ini_set('display_errors',0);
  this_function_does_not_exist();
  echo "ok";
?>

This returns an empty page with status code 200:
-----
HTTP/1.1 200 OK
Date	Fri, 12 Mar 2010 07:27:15 GMT
Server	Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny6 with Suhosin-Patch
X-Powered-By	PHP/5.2.6-1+lenny6
Vary	Accept-Encoding
Content-Encoding	gzip
Content-Length	20
Keep-Alive	timeout=15, max=100
Connection	Keep-Alive
Content-Type	text/html
-----

Content-Length is 20, probably because of gzip? There are no spaces around PHP block in source code.

I have checked phpinfo() and display_errors is set to Off, so there is no error there. Also, I have tried setting it in php.ini - no change.

Another problem: parse errors are also not handled correctly (even if display_errors is set to 0 in php.ini). See previous poster's example. 

Thanks!
 [2010-03-12 16:04 UTC] pajoye@php.net
-Operating System: Windows IIS6 +Operating System: *
 [2010-08-12 15:35 UTC] tyra3l at gmail dot com
I can reproduce the problem.
I found out, that if I enable xdebug, then I get header 200, if I disable it, then 
it's 500.
Will report it to Derick.

Tyrael
 [2010-08-12 15:40 UTC] tyra3l at gmail dot com
It's seems that this is a known bug in the xdebug, see:
http://bugs.xdebug.org/view.php?id=587

but couldn't fix it without making some changes in php itself:

"Before I can address this, there need to be some changes in PHP itself. It 
doesn't expose some required information to extensions yet that I will need."

I hope this get fixed soon.

Tyrael
 [2010-11-19 11:48 UTC] dean at deansas dot org
> The reason why display errors needs to be turned of, is because
> displayed errors generate output, and output causes the headers 
> to be send out. I'm afraid we can't do much about this.

Can't PHPs error handling first set a 500 header and then output
error messages as appropriate? 

It doesn't seem to me like this is something that can never ever be fixed
 [2013-04-13 19:01 UTC] matteosistisette at gmail dot com
The status is wrong. And oh my god, since 2010!!

This IS a bug.

Display_errors off means don't DISPLAY errors, it shouldn't have any effect on 
the response code.

Default response for fatal errors should be 500 whether or not display_errors is 
turned on.
 [2013-05-28 21:42 UTC] kwintersnc at gmail dot com
According to http://bugs.xdebug.org/view.php?id=587 this is fixed in PHP 5.4, so 
"Not a bug" isn't correct.
 [2014-04-28 14:40 UTC] ruben at rubensayshi dot com
still having this issue with "PHP Version: 5.4.27-1+deb.sury.org~precise+1" with xdebug turned on or off, doesn't seem to make a difference ...

display_errors off does, as already stated by others.
 [2014-06-02 15:21 UTC] brenjt at gmail dot com
I can also confirm the issue still exists: PHP Version 5.4.16
 [2014-06-24 22:01 UTC] derek at derekperkins dot com
This is an error for us as well, running on 5.4.28 on Google App Engine, with and without XDebug. This definitely needs to be fixed.
 [2014-06-25 08:10 UTC] tyrael@php.net
the xdebug issue was a separate problem, and is indeed fixed.
what is still not "fixed" is that if you enable display_errors, then the error message itself will trigger sending out the response which sets the http 200 implicitly.
if we go ahead and change this, we should make sure to only add the http 500 when the script execution is actually terminated by the error(for example E_RECOVERABLE_ERROR will or won't stop the execution based on the return value of the user defined error handler) as we don't wanna start sending http 500 responses for every notice and stuff.
 [2014-06-25 08:57 UTC] tyrael@php.net
oh, it seems we are explicitly checking for display_errors when setting the 500 response code:
http://lxr.php.net/xref/PHP_5_4/main/main.c#1154
I will ask the others on the internals list for the reason for this.
 [2014-07-08 17:19 UTC] jonathan at spoonity dot com
A workaround for those interested is the following:

register_shutdown_function(function() {
    $error = error_get_last();
    if ($error['type'] == E_ERROR) {
        header('HTTP/1.1 500 Internal Server Error');
    }
});

Be nice to see this fixed without this workaround though.
 [2014-07-08 19:28 UTC] tyrael@php.net
-Status: Not a bug +Status: Re-Opened
 [2014-07-08 19:28 UTC] tyrael@php.net
here is the thread I've started about this behavior:
http://www.serverphorums.com/read.php?7,965893
it turned out that we added the explicit display_errors check for not setting the http 500 response code because Internet Explore will show a custom error page for non-2xx responses if the length of the response body is less than an arbitrary threshold, hence it won't show the error message if we set the http 500.
I don't think that this change was a good idea back then, but it is possible that changing it now would cause more harm than good.
I will keep this ticket open until we either reach a consensus that this should be fixed in a future release, or should be kept as-is and the documentation is updated to reflect current behavior.
 [2014-07-08 20:38 UTC] jonathan at spoonity dot com
Ah yes, I remember that. The IE limit a minimum of 512 byte of data to show  the outputted data. Perhaps there could be an ini setting to choose if the status code will be 200 or 500, with the default being the current behaviour?
 [2015-05-25 17:33 UTC] josh dot ribakoff at gmail dot com
+1

This is a BUG in my books. Until it is fixed, I can't simply tail an error log. Instead I'd have to go manually exercise every feature & invoke every code path in my app & painstakingly analyze the network responses of all my ajax calls to detect any possible errors. Horrible.
 [2015-07-20 10:17 UTC] xmeltrut at gmail dot com
I would agree that this is a bug. If there has been a server error, we should not be returning a 200 response. If IE then does not display it, that is a problem for IE to look at. The wrong header causes a lot of problems, especially for AJAX>
 [2015-11-29 06:28 UTC] admin at mcnaughton dot media
Not just `display_errors = off`. I believe this effects `display_errors = stderr` as well for similar reasons.
 [2015-11-29 21:32 UTC] anzenews at volja dot net
I can't believe this hasn't been solved yet. It has been more than 5 years people! RFC 2616 is very clear on proper HTTP status codes (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). If some obscure browser handles return codes improperly, that should be solved there, not in PHP. This is not 1990s anymore, IE is far from being a dominant browser anymore. 

So how about fixing this the right way? Just return status 5xx on parsing and similar errors, as recommended (SHOULD) by HTTP 1.1 protocol. It shouldn't be that difficult.
 [2015-12-12 22:17 UTC] http at sendspamhere dot com
You can't completely fix this by the way http works.

    <?php
    echo 'x';
    ob_flush(); // http status code and headers are now sent to client
    eval('x=y'); // error detected here

no matter which technology stack, after you've  sent everything is 200 OK you can't signal the client something went wrong. You shouldn't monitor your service through status codes only because of this edge case. Monitor your logs.
 [2015-12-14 09:17 UTC] phpbug at starurl dot com
Disagree with above commenter - HTTP status codes are *designed* for monitoring the status of web services. Saying check the logs assumes the user has access to the logs - could be a shared host without log access, a third-party's service, or monitoring from an external uptime checker.

Sure - if headers have already been sent, not a lot PHP can do about that (though a basic HTTP 500 warning message would be better than the current blank page). But at the moment it doesn't matter if headers have been sent or not - PHP fails to return the correct 500 status code, which just about every other stack manages just fine.

After reporting this over 5 years ago, and it was known long before that, I'm at loss how something so basic hasn't been fixed yet.
 [2015-12-14 09:27 UTC] phpbug at starurl dot com
Also - output buffering is enabled by default, no? So doesn't matter if output already sent, the status code can be overridden surely? 

And again, even if headers already sent, at least get the string '500 Internal Server Error' (as would happen if display_errors was off) into the output so the user has some clue something went wrong. How does displaying *less* error information if 'display_errors=true' make any sense? ;)
 [2015-12-14 17:31 UTC] josh dot ribakoff at gmail dot com
Yes, just because 1% of programmers may be using ob_flush() doesn't mean the other 99% are. Most PHP frameworks (Zend, Symfony, Silex) use some sort of controller that returns a response at the end of the request only. Specifically this is a big issue for ajax, which I'm pretty sure is impossible to use ob_flush() with, seeing as you need to build up a full response & output it at the end with json_encode() in its entirety.
 [2016-07-12 18:05 UTC] chealer at gmail dot com
I am experiencing this symptom under WampServer 2.5, which uses PHP 5.5.12. This happens even after disabling Xdebug, and even though display_errors is set to On. Is this caused by the same bug?

I agree with jonathan, josh and xmeltrut; a preference could be introduced, but the default behavior should not be the current behavior.
 [2017-10-06 13:21 UTC] antoine dot gilabert at gmail dot com
i've done this to solve the problem:
register_shutdown_function( "fatal_handler" );
function fatal_handler() {
    http_response_code (500);
}
 [2017-11-06 21:19 UTC] chealer at gmail dot com
I still experience this with XAMPP 5.6.30's PHP 5.6.30.
 [2018-05-25 02:51 UTC] robberphex at gmail dot com
I'm trying to fix this.
Please review https://github.com/php/php-src/pull/3244.

And, Xdebug have same bug. If you are interested, see https://github.com/xdebug/xdebug/pull/420
 [2018-07-10 15:07 UTC] drew+bug dot php dot net at mcdruid dot co dot uk
Note that this may sometimes be down to the CustomLog format in apache. For example '%>s' can (correctly) yield a 403 in the access log whereas just '%s' may record a 200 even when the status code of the response was something else.
 [2019-04-24 21:56 UTC] danny dot boisvert at cogecomedia dot com
Just so you know, I had this same issue and I had to change my "error_reporting" value to the resolved integer value 
("E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED" -> 30711) 
[Based on this: https://www.php.net/manual/en/errorfunc.constants.php] 
since I'm trying to use an environment variable within the configuration file and it doesn't seem to resolve the constants properly.
 [2023-11-17 10:49 UTC] david at ols dot es
in php 8.2 it returns a 200 response code even if using header and http_response_code

<?php

register_shutdown_function('shutdown_handler');

echo "Hello";

while(true) $data .= str_repeat('#', PHP_INT_MAX);
    
function shutdown_handler()
	{
	header($_SERVER['SERVER_PROTOCOL'].' 500 Internal Server Error', true, 500);
	http_response_code(500);
	print_r(error_get_last());
	}
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 14:01:29 2024 UTC