Page MenuHomePhabricator

PHP Warning from /w/thumb.php: "Cannot modify header information - headers already sent"
Closed, ResolvedPublicPRODUCTION ERROR

Description

Error

Request URL: commonswiki thumbnail proxy
Request ID: XPjEdQpAMFgAABuWMJYAAAAY

message
ErrorException from line 649 of /srv/mediawiki/php-1.34.0-wmf.8/thumb.php: PHP Warning: Cannot modify header information - headers already sent
ErrorException from line 638 of /srv/mediawiki/php-1.34.0-wmf.8/thumb.php: PHP Warning: Cannot modify header information - headers already sent
ErrorException from line 675 of /srv/mediawiki/php-1.34.0-wmf.8/thumb.php: PHP Warning: Cannot modify header information - headers already sent
ErrorException from line 637 of /srv/mediawiki/php-1.34.0-wmf.8/thumb.php: PHP Warning: Cannot modify header information - headers already sent
trace
#0 /srv/mediawiki/php-1.34.0-wmf.8/thumb.php(649): MWExceptionHandler::handleError(integer, string, string, integer, array, array)
#1 /srv/mediawiki/php-1.34.0-wmf.8/thumb.php(326): wfThumbError(integer, string, NULL, array)
#2 /srv/mediawiki/php-1.34.0-wmf.8/thumb.php(38): wfStreamThumb(array)
#3 /srv/mediawiki/w/thumb.php(3): include(string)
#4 {main}

Impact

Response might be corrupt.

Notes

Started happening today on wmf.8.

capture.png (1×2 px, 69 KB)

Event Timeline

zeljkofilipin triaged this task as Unbreak Now! priority.Jun 6 2019, 11:49 AM
zeljkofilipin subscribed.

Train blockers are unbreak now priority.

Reedy lowered the priority of this task from Unbreak Now! to High.Jun 6 2019, 1:08 PM
Reedy subscribed.

Looking at logstash over the last 24H... There was no results in the last 1H for this

Screenshot 2019-06-06 at 14.06.29.png (432×2 px, 74 KB)

This isn't a train blocker

We should probably use WebResponse which can log where the headers were sent.

Change 514732 had a related patch set uploaded (by Gergő Tisza; owner: Gergő Tisza):
[mediawiki/core@master] Log headers sent errors more usefully in thumb.php

https://gerrit.wikimedia.org/r/514732

Change 514732 merged by jenkins-bot:
[mediawiki/core@master] Log headers sent errors more usefully in thumb.php

https://gerrit.wikimedia.org/r/514732

Change 516495 had a related patch set uploaded (by Krinkle; owner: Gergő Tisza):
[mediawiki/core@wmf/1.34.0-wmf.8] Log headers sent errors more usefully in thumb.php

https://gerrit.wikimedia.org/r/516495

Change 516495 merged by jenkins-bot:
[mediawiki/core@wmf/1.34.0-wmf.8] Log headers sent errors more usefully in thumb.php

https://gerrit.wikimedia.org/r/516495

Mentioned in SAL (#wikimedia-operations) [2019-06-12T18:15:55Z] <krinkle@deploy1001> Synchronized php-1.34.0-wmf.8/thumb.php: T225197 / rMW06b631fae560 (duration: 00m 47s)

Krinkle renamed this task from "PHP Warning: Cannot modify header information - headers already sent" from /w/thumb.php to PHP Warning from /w/thumb.php: "Cannot modify header information - headers already sent".Jun 12 2019, 6:17 PM
Krinkle removed a project: Patch-For-Review.

New information from this error from the above debug instrumentation:

PHP Warning: Cannot modify header information - headers already sent by (output started at /srv/mediawiki/php-1.34.0-wmf.15/includes/libs/http/MultiHttpClient.php:416)

#0 [internal function]: MWExceptionHandler::handleError(integer, string, string, integer, array)
#1 /srv/mediawiki/php-1.34.0-wmf.15/thumb.php(646): header(string)
#2 /srv/mediawiki/php-1.34.0-wmf.15/thumb.php(330): wfThumbError(integer, string, NULL, array)
#3 /srv/mediawiki/php-1.34.0-wmf.15/thumb.php(38): wfStreamThumb(array)
PHP Warning: Cannot modify header information - headers already sent by (output started at /srv/mediawiki/php-1.34.0-wmf.15/includes/libs/http/MultiHttpClient.php:416)

#0 [internal function]: MWExceptionHandler::handleError(integer, string, string, integer, array)
#1 /srv/mediawiki/php-1.34.0-wmf.15/thumb.php(683): header(string)
#2 /srv/mediawiki/php-1.34.0-wmf.15/thumb.php(330): wfThumbError(integer, string, NULL, array)
#3 /srv/mediawiki/php-1.34.0-wmf.15/thumb.php(38): wfStreamThumb(array)

So looks like MultiHttpClient might be at fault?

mmodell changed the subtype of this task from "Task" to "Production Error".Aug 28 2019, 11:06 PM

This seems to be a secondary error, triggered while trying to report another error. As far as I can tell from looking at the code for five minutes, this seems to be happening:

  • In line 321 of thumb.php, we call $status = $img->getRepo()->streamFileWithStatus( $thumbPath, $headers ) which tries to send the file, and starts generating output, but hits an error at some point.
  • $status->isOK() returns false in line 324, so wfThumbError() is called in 329.
  • wfThumbError() tries to set a header in line 645, which triggers "PHP Warning: Cannot modify header information"

Seems to me like wfThumbError() should not tried to send HTML output if output was already sent.
Also, we should probably log the original error somewhere, somehow. As far as I can tell, that doesn't happen at all.

Change 562592 had a related patch set uploaded (by Daniel Kinzler; owner: Daniel Kinzler):
[mediawiki/core@master] thumb.php: don't try to send errors after data has been sent.

https://gerrit.wikimedia.org/r/562592

Change 562592 merged by jenkins-bot:
[mediawiki/core@master] thumb.php: don't try to send errors after data has been sent.

https://gerrit.wikimedia.org/r/562592

@daniel Remember to enable the thumb channel in production, or, given this is probably temporary instrumentation, perhaps use AdhocDebug instead (and cherry-pick to wmf, leave unmerged in master).

@daniel Remember to enable the thumb channel in production, or, given this is probably temporary instrumentation, perhaps use AdhocDebug instead (and cherry-pick to wmf, leave unmerged in master).

The new code reports errors exactly in the same way that is already done if an error occurs before streaming starts. The channel isn't new, and it's not temporary. I'd expect that channel to already be enabled?...

Those two lines using thumb are the only two in the codebase that use that channel. The previous one being introduced in 2015 and never enabled in prod from what I can see. There is however a more common thumbnail channel enabled in prod.

What is the long term purpose of this check? It seems to me not like a runtime error but a logical error in the code. Which, once we find the root cause, can be fixed and then removed. The contract of this function is to produce an http response. Something else making an HTTP response and letting execution continue until here is a bug. I don't think we intend to add similar checks everywhere in the codebase where an HTTP header or some content is output? If not, why is this one special? Note that PHP already covers our basis for the general ability to detect such mistakes from creeping back in (we'd know about it).

Those two lines using thumb are the only two in the codebase that use that channel. The previous one being introduced in 2015 and never enabled in prod from what I can see. There is however a more common thumbnail channel enabled in prod.

Good point, perhaps we should use that channel instead.

What is the long term purpose of this check? It seems to me not like a runtime error but a logical error in the code. Which, once we find the root cause, can be fixed and then removed. The contract of this function is to produce an http response. Something else making an HTTP response and letting execution continue until here is a bug. I don't think we intend to add similar checks everywhere in the codebase where an HTTP header or some content is output? If not, why is this one special? Note that PHP already covers our basis for the general ability to detect such mistakes from creeping back in (we'd know about it).

The root cause of the "Cannot modify header information - headers already sent" warning is found and fixed by this patch: it happens when an error occurs during streaming. The old code would try to set a status header, but that would fail because the stream already started. The new code logs the original error instead.

The code that has already started to send a response is indeed known: it's line 326:

$status = $img->getRepo()->streamFileWithStatus( $thumbPath, $headers );

this generates a HTTP response, and returns a Status if something goes wrong. We were previously mishandling the case of something going wrong after output had already started.

Change 565152 had a related patch set uploaded (by Daniel Kinzler; owner: Daniel Kinzler):
[mediawiki/core@master] thumb.php: Use 'thumbnail' channel to report errors

https://gerrit.wikimedia.org/r/565152

I assume this is resolved now.

Change 565152 merged by jenkins-bot:
[mediawiki/core@master] thumb.php: Use 'thumbnail' channel to report errors

https://gerrit.wikimedia.org/r/565152