Codegento Who Let Mage Out Of The Cage?

14Mar/116

Debugging “HEADERS ALREADY SENT” error

Sometimes Magento throws the "HEADERS ALREADY SENT" error to the system.log and it can be quite frustrating determining where headers were already sent.  Especially when working on a shared codebase and you're pretty sure that you and your team haven't done anything to cause this new error.  All you normally get in the system.log file is the error message and a stacktrace to where that exception was thrown from.  Nothing about where the headers were previously sent.  It would be nice if Magento would tell us the exact file and line that is causing the problem.  Turns out that Magento does know this information and we can do a little tweak to send it to the log.

That error is thrown from Mage_Core_Controller_Response_Http -> sendHeaders().  This function calls the super class function that actually does the check to see whether or not headers have already been sent, Zend_Controller_Response_Abstract -> canSendHeaders().

The Zend_Controller_Response_Abstract class handles, among other things, sending response headers and tracking the last time the headers were sent (and from what file and line).  Here is what that function looks like, and where we'll make a change:

public function canSendHeaders($throw = false) {
    $ok = headers_sent($file, $line);
    if ($ok && $throw && $this->headersSentThrowsException) {
        #require_once 'Zend/Controller/Response/Exception.php';
        throw new Zend_Controller_Response_Exception('Cannot send headers; headers already sent in ' . $file . ', line ' . $line);
    }
    return !$ok;
}

You'll notice the code inside the if statement attempts to include the file and line that previously sent headers in the exception message.  More often than not the $throw param isn't passed in so the exception isn't thrown and that useful message is never seen.

Since we really need to get at that information, add the following code immediately before the return:

if ($ok) {
    Mage::log('Cannot send headers; headers already sent in ' . $file . ', line ' . $line);
}

The $ok variable is a little confusing since it really means "have headers already been sent."  The added code will log the offending file and line in system.log immediately before the exception shows up.  Now, navigate to that file and see if there is an inadvertent echo or var_dump or something else that's causing the problem.

Once you have the problem fixed make sure you revert these changes since we don't like changing Core code.

Posted by Trent Ohannessian

Comments (6) Trackbacks (0)
  1. Should this give me more info in my .log files? Nothing has changed here.

    • Yes, you should see more info in your log files. You should see lines similar to the the line we’re logging in the last code snippet:

      ‘Cannot send headers; headers already sent in ‘ . $file . ‘, line ‘ . $line

      And that should tell you which file and line the headers were already sent.

      Do you have logging enabled? Does the mage log file exist and contain other current information?

  2. Thank you very much for this tip, I found easily the concerned file and it was just a blank space before <?php
    difficult to find without the file name in the log file.

  3. THE TEXT FILE SHOULD NOT BE IN UTF-8, but it should be UTF8(without BOM) !!!!!!

  4. Hi, can’t find

    Zend_Controller_Response_Abstract -> canSendHeaders().

    in Magento 1.9

    any help?


Leave a comment

(required)

Trackbacks are disabled.