How to Fix the “Headers Already Sent” Error in PHP

Updated for 2026 | Covers login redirects, sessions, and cookies

Your PHP login was working, you added a redirect after a successful sign in, and suddenly the page throws a warning about headers and refuses to redirect. The “headers already sent” error is one of the most confusing messages for beginners because the fix is almost never where the error points. Once you understand the one rule behind it, it becomes simple to fix and easy to avoid forever.

Warning: Cannot modify header information – headers already sent by (output started at /login.php:2) in /login.php on line 18

The one rule that causes this error

Here is the entire reason this error exists, in one sentence: functions that send HTTP headers must run before any output is sent to the browser.

The functions that send headers are the ones like header(), session_start(), and setcookie(). “Output” means anything that gets sent to the page: an echo, HTML outside your PHP tags, even a single blank space before . The moment any output goes out, PHP locks the headers. If you then try to set a header, you get the error.

Think of it like mailing a letter

The headers are the address on the envelope, and the output is the letter inside. Once you have dropped the envelope in the mailbox (sent output), you cannot rewrite the address (set headers). Everything below is just finding what sent output too early.

How to read the error message correctly

The error gives you two locations, and beginners read the wrong one. Look again:

headers already sent by (output started at /login.php:2) in /login.php on line 18

Line 18 is where you tried to set the header. That is not your bug. The part in parentheses, output started at /login.php:2, is the real clue. It tells you output first escaped on line 2. That is where you look. Fix line 2, and line 18 starts working. Always read the “output started at” location, not the line at the end.

Cause 1: whitespace before the opening PHP tag

This is the most common cause by far. If there is any space, tab, or blank line before , that counts as output. The file looks empty at the top, but it is not:

 <-- a blank line or space here sends output

The fix is to make sure is the very first thing in the file, character one, line one, with nothing before it:

// nothing at all before this tag
header("Location: dashboard.php");
exit();
?>
Tip

For files that are pure PHP with no HTML, leave off the closing ?> tag entirely. A stray newline after the closing tag is another sneaky source of output. Pure PHP files do not need it.

Cause 2: echo or HTML before a redirect

If you print anything, even a success message, before redirecting, the redirect fails:

echo "Login successful!";   // this sends output
header("Location: dashboard.php");   // now this fails
?>

You cannot show a message and then redirect with header() in the same breath, because the message is output. The correct approach is to redirect first and show the message on the next page. A common pattern is to pass it through the session or the URL:

Then on dashboard.php you read and display that message. The redirect works because nothing was printed before it.

Cause 3: the invisible BOM character

Sometimes the top of your file looks perfectly clean and you still get the error. The culprit can be an invisible character called a byte order mark, or BOM, that some editors add when saving a file as UTF-8. You cannot see it, but PHP sends it as output.

The fix is to re-save the file using “UTF-8 without BOM” encoding. In VS Code, you can click the encoding label in the bottom status bar, choose Save with Encoding, and pick UTF-8 (not UTF-8 with BOM). The invisible character is removed and the error clears.

Editor setup helps

A properly configured editor prevents BOM and stray whitespace issues before they happen. Our guide to the best VS Code setup for PHP developers covers the settings that stop these silent output problems.

Cause 4: session_start() after output

Because session_start() sends a session cookie header, it follows the same rule. This fails:

echo "Welcome";
session_start();   // too late, output already sent
?>

The fix is to call session_start() at the very top of the page, before any echo or HTML:

// first thing, before any output
echo "Welcome";
?>

A reliable habit: every page that uses sessions starts with session_start() on the first line after . No exceptions.

The correct order for login and redirect code

Putting it all together, here is the structure that avoids this error completely in a login flow. Notice that all the header-sending work happens at the top, before a single character of HTML:

// 1. Session and header work FIRST, no output above this
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // ... check the username and password ...
    if ($validLogin) {
        $_SESSION['user_id'] = $userId;
        header("Location: dashboard.php");
        exit();   // always exit after a redirect
    }
}
?>




  
...
Always exit

Notice the exit(); right after every header("Location: ..."). Without it, the script keeps running and can execute code you meant to skip. A redirect should always be followed by exit.

Frequently asked questions

Why does the error point to a line that looks fine?

Because the line at the end of the error is where you tried to set the header, not where output started. The real cause is in the “output started at” location in the parentheses, which is usually near the top of the file. Fix that location, not the line the error ends with.

Can I just turn off the warning to make it go away?

You can suppress the warning, but the redirect or session still will not work, because the underlying problem remains. Suppressing it hides the symptom and leaves your login broken. Fix the early output instead, which actually makes the feature work.

What is output buffering and should I use it?

Output buffering with ob_start() holds output in memory so headers can still be sent later. It works as a fallback, but it hides messy code structure rather than fixing it. For beginners it is better to put header work at the top of the file, which is cleaner and teaches the right habit.

I get this only on a downloaded project, not my own code. Why?

Downloaded files are often saved with a BOM or have trailing whitespace from being edited on different systems. Re-save the offending file as UTF-8 without BOM, and check for blank lines before the opening PHP tag. That clears it in most downloaded projects.

Once you internalize the rule that headers come before output, this error stops being mysterious. Set sessions and redirects at the top, output HTML below, and you will rarely see it again. Practice on any complete project from the PHP source code library.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top