Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
PHP has already started sending the response, but session_start() still needs to send session headers. Move session initialization to the request’s entry point, before HTML, whitespace, debugging output, included templates, cookies, or redirects. Then inspect the location named after output started at—that is usually where the real problem begins.
What the warning means
A PHP response has two parts:
- HTTP headers: cookies, redirects, cache rules, content type, and status codes.
- Response body: HTML, text, warnings, whitespace, and debugging output.
Once PHP sends body output, it may no longer be able to add or change HTTP headers. session_start() commonly sends a session cookie and other session-related headers, so it must run before any browser output. See the PHP documentation for session_start() and the documentation for header().
The HTML <head> element is unrelated to HTTP headers. A file named head.html.php can still emit response content and cause the warning.
Recommended Free Tools
How to read the error
Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /path/index.php:1) in /path/includes/access.inc.php on line 42
There are two important locations:
index.php:1is where PHP believes output first began. Inspect this location first.access.inc.php:42is where the latersession_start()call failed. It is usually the symptom, not the original mistake.
Older PHP versions used wording such as session_start() [function.session-start]. That syntax is historical; the underlying problem is the same.
#1 Best Overall
The fastest correct fix
Start the session before loading anything that might render output:
<?php
session_start();
require_once __DIR__ . '/includes/initialize.php';
require_once __DIR__ . '/includes/access.inc.php';
// Process POST requests, authentication, cookies, and redirects here.
// Render HTML only after that work is complete.
A common failing arrangement looks like this:
<?php
require 'includes/head.html.php'; // Emits HTML
require 'includes/access.inc.php'; // Calls session_start()
Use this order instead:
<?php
session_start();
require 'includes/access.inc.php';
require 'includes/head.html.php';
session_start() does not have to be literally the first byte of the file—comments and PHP declarations may precede it—but no response output may occur first.
Find the first output
Inspect the file and line shown after output started at, then check every file included before the failing call. Look for:
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #2
echo,print,print_r(), orvar_dump()- raw HTML before the PHP call
- included templates that render markup
- PHP warnings, notices, or deprecation messages
- accidental whitespace or invisible characters
- auto-prepended files or framework bootstrap code
You can ask PHP to report the origin programmatically:
<?php
$file = null;
$line = null;
if (headers_sent($file, $line)) {
error_log("Headers already sent in {$file}:{$line}");
}
session_start();
headers_sent() can provide the file and line where output began. A temporary die() can help during local debugging, but never expose server filesystem paths to visitors in production.
Hidden output: whitespace and UTF-8 BOMs
Visible HTML is not required to trigger the warning. Check for:
- a blank line or spaces before
<?php - whitespace after a closing
?>tag - a UTF-8 byte-order mark (BOM) at the beginning of a file
- a stray character in an included file
- debug output left in a shared bootstrap file
- an error message displayed before session initialization
PHP-only files should normally omit the closing tag:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problems<?php
function userIsLoggedIn(): bool
{
return false;
}
UTF-8 itself is not the problem. The issue is an emitted BOM. If the first output location seems mysterious, save the file as UTF-8 without BOM and inspect its raw bytes. On systems with xxd available:
xxd -g 1 -l 16 path/to/file.php
The UTF-8 BOM sequence is:
ef bb bf
You can also search a project for likely causes:
grep -RInE 'session_start|headers*(|setcookies*(|echos|print_rs*(|var_dumps*(' .
grep -RInE '?>' --include='*.php' .
Separate session setup, request handling, and templates
The historical SitePoint example started sessions inside an authentication function after page markup had already been included. Moving the call into a function does not help if that function runs too late.
Rank #4
A clearer structure is:
- Bootstrap: start the session and load configuration.
- Controller: process forms, authentication, cookies, and redirects.
- Template: render HTML after request processing finishes.
For example:
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'login') {
// Validate credentials with password_verify().
// After successful authentication:
session_regenerate_id(true);
$_SESSION['user_id'] = $userId;
header('Location: dashboard.php');
exit;
}
if ($action === 'logout') {
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}
session_destroy();
header('Location: login.php');
exit;
}
}
require __DIR__ . '/templates/page.php';
Use session_regenerate_id(true) after successful login to reduce session-fixation risk. Store a user ID and minimal authorization state in the session—not a plaintext password or a reusable password-derived value. Passwords should be checked with password_hash() and password_verify().
Prevent repeated session initialization
Centralizing session startup is preferable. If a shared bootstrap can be loaded by multiple entry points, guard it when necessary:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →<?php
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
This prevents redundant initialization but does not repair output that has already occurred. The bootstrap must still run before rendering. See PHP’s session_status() documentation.
Should you use ob_start()?
Output buffering delays body output:
<?php
ob_start();
session_start();
echo 'Page content';
ob_end_flush();
That can be legitimate when an application intentionally buffers a complete response, captures template fragments, or applies a deliberate output transformation. PHP documents this behavior in its output-control documentation.
However, adding ob_start() globally just to silence the warning is usually a poor permanent fix. It can hide incorrect execution order, increase memory use, alter error visibility, and make redirects or output handlers harder to reason about. Remove the accidental output and move session, cookie, and redirect logic earlier whenever possible.
Why it works locally but fails after deployment
Different environments may use different settings for output buffering, error display, automatic session startup, encoding, included files, or session storage. Relevant settings include:
session.auto_startsession.use_cookiesandsession.use_only_cookiessession.cookie_secure,session.cookie_httponly, andsession.cookie_samesitesession.save_path
Review the PHP session configuration documentation. A development warning displayed in the response can itself become the first output, so fix the underlying warning and configure production systems to log errors rather than display them to visitors. Do not use @session_start() to suppress the problem.
Final troubleshooting checklist
- Read the entire warning, especially
output started at FILE:LINE. - Inspect that file, including bytes before
<?php. - Check all parent files and includes executed earlier.
- Move
session_start()to the request entry point. - Remove HTML, debugging output, warnings, whitespace, and BOMs before it.
- Ensure
setcookie()andheader()also run before output. - Use
headers_sent($file, $line)when the source is unclear. - Use a
session_status()guard only to avoid duplicate startup. - Use output buffering only as an intentional response-management technique.
- Test a new session, login, invalid credentials, refresh, logout, redirects, and deployment settings.
For web requests, the durable solution is nearly always the same: initialize the session and complete request processing first, then render the response.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

