Ffile2fix
Sign in Get started

How to fix "session_start(): Session cannot be started" in PHP

Warning: session_start(): Session cannot be started after headers have already been sent in /home/user/public_html/login.php on line 3

session_start() needs to send a cookie header, but the page has already sent output to the browser, so PHP cannot start the session. Any HTML, echo, whitespace or BOM before session_start() causes it.

Also appears as: Warning: session_start(): Cannot start session when headers already sent (PHP 7.2-7.4) · Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /path/header.php:1) · Warning: session_start(): Cannot send session cache limiter - headers already sent

Common causes

  • HTML or an included header template is output before session_start()
  • Whitespace or a UTF-8 BOM before <?php in the file or an included file
  • A PHP warning printed to the page before session_start() runs
  • session_start() called inside a template partway through the page
  • In WordPress, a plugin calling session_start() too late, such as inside a shortcode or template

How to fix it

  1. Move session_start() to the very top. Call it on the first lines of the entry script, before any include that outputs HTML. A shared bootstrap file is the best place.
  2. Find the output that came first. Use headers_sent($file, $line) just before session_start() and log $file:$line, or read 'output started at' in the related warning.
  3. Remove whitespace and BOM. Ensure nothing precedes <?php, drop closing ?> tags in PHP-only files, and save files as UTF-8 without BOM.
  4. Start the session only once and only if needed. Guard with if (session_status() === PHP_SESSION_NONE) so multiple includes do not try again.
  5. Use the right WordPress hook. Start sessions early on the init hook, not inside templates or shortcodes, and close them with session_write_close() to avoid blocking REST and loopback requests.
  6. Keep warnings out of output. Set display_errors = Off in production so a stray notice cannot become the output that blocks the session.

bootstrap.php

<?php
if (session_status() === PHP_SESSION_NONE) {
    session_start([
        'cookie_httponly' => true,
        'cookie_secure'   => true,
        'cookie_samesite' => 'Lax',
    ]);
}

How to stop it happening again

  • Start sessions in one bootstrap file included first
  • Omit closing ?> tags and save files without BOM
  • Never call session_start() from templates

Frequently asked questions

Why does it work locally but not on the server?

Local PHP often has output_buffering enabled, which delays output until the end. The production server may have it off, so the same whitespace breaks session_start().

Does ob_start() fix it?

Starting an output buffer at the very top hides the problem, but you should still remove the stray output and move session_start() earlier.

What happens to $_SESSION when this fails?

The session is not started, so values are not saved between requests. Logins and carts appear to forget the user on the next page.