If you've ever seen a bright red block of PHP text at the very top of a WordPress page — "Warning: Cannot modify header information - headers already sent by (output started at /home/username/public_html/wp-config.php:1)" — you already know it isn't exactly self-explanatory. The page usually still loads under the warning, which makes it feel harmless. It isn't always. That same warning is often the reason login redirects loop, plugin activation silently fails, or a payment gateway won't send you back to a success page. Here's what's actually happening and how to track it down on a cPanel-hosted WordPress site.
What the Warning Actually Means
PHP sends HTTP headers — redirects, cookies, content-type — before any actual page output. Once even a single byte of output (HTML, whitespace, a stray character) has been sent to the browser, the headers for that request are locked in. If your code, or WordPress core, or a plugin tries to call header() or wp_redirect() after that point, PHP can't comply, so it throws this warning instead of silently failing.
In WordPress specifically, this usually shows up during login (wp-login.php redirecting to wp-admin), after saving settings, during a plugin or theme switch, or on any AJAX endpoint that needs to set a cookie.
The Usual Suspects
Nine times out of ten, it's one of these three things.
1. Whitespace or a Byte Order Mark Before <?php
If wp-config.php, a theme's functions.php, or a plugin file has even one blank line or space before the opening <?php tag, PHP treats that as output. The same goes for a Byte Order Mark (BOM) — an invisible three-byte marker some Windows editors and FTP clients silently add when a file is saved as "UTF-8." You won't see it by eye; you'll only see it in the error, which almost always points at line 1 of the offending file.
2. Something Echoing Before a Redirect
A theme that echoes a deprecation notice, a plugin that prints debug output, or a custom snippet with a stray print_r() left in — any of these can run before WordPress tries to redirect the user, and that's enough to break it.
3. A Trailing ?> Closing Tag
PHP files that end with ?> followed by so much as a blank line or a space are a classic cause. WordPress core's own coding standard omits the closing tag entirely in pure-PHP files for exactly this reason.
Finding the Exact File and Line
The warning text tells you almost everything you need:
Warning: Cannot modify header information - headers already sent by
(output started at /home/yourusername/public_html/wp-config.php:1)
in /home/yourusername/public_html/wp-includes/pluggable.php on line 1330
Read it as two locations, not one. "Output started at" is where the actual problem lives — in this example, line 1 of wp-config.php. "In ... on line 1330" is just where WordPress noticed and complained; that second file is rarely the one you need to edit.
If the message doesn't show up on screen because WP_DEBUG_DISPLAY is off, turn on logging instead. In wp-config.php, above the line that says /* That's all, stop editing! */, add:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Reproduce the issue, then check wp-content/debug.log in cPanel File Manager for the same "output started at" line.
Fixing It
Once you know the file:
- Open it in cPanel's File Manager (or via SFTP) using the plain code editor, not the HTML editor — the code editor won't reformat anything.
- Check line 1. If there's any character — space, tab, blank line — before
<?php, delete it so the very first character in the file is<. - Check the end of the file. If it ends in
?>, delete the closing tag and everything after it. PHP runs fine without it. - If line 1 looks empty but the error still points there, it's probably a BOM. File Manager's editor won't show it. Re-save the file with a plain text editor set to "UTF-8 without BOM" (in VS Code: click the encoding label in the bottom-right corner, choose "Save with Encoding," then "UTF-8"), and re-upload to overwrite the original.
- If the culprit is a plugin or theme file rather than
wp-config.php, deactivate that plugin by renaming its folder inwp-content/plugins/through File Manager to force-deactivate it, and confirm the warning goes away. That confirms the source before you dig into its code or contact the plugin author.
A Band-Aid: Output Buffering
If you need the redirect working right now and can't immediately find the offending file, output buffering will paper over it. Add this as the very first line of wp-config.php, right after <?php:
ob_start();
This tells PHP to hold output in a buffer instead of sending it immediately, so a late header() call still succeeds. It works, but it's a workaround, not a fix — the stray output is still there, and output buffering can mask other problems or add a small amount of memory overhead on high-traffic pages. Treat it as a temporary measure while you track down the real cause, not a permanent setting.
Quick Reference
| Symptom | Likely Cause | Fix |
|---|---|---|
| Error points to wp-config.php line 1 | Whitespace or BOM before <?php | Re-save file as UTF-8 without BOM, strip leading blank lines |
| Error points to a plugin file | Debug output or echo before a redirect | Deactivate the plugin; report to the author or remove the stray output |
| Error points to theme's functions.php | Trailing ?> with extra characters after it | Delete the closing tag and anything after it |
| Happens only on login or checkout | Output sent before wp_redirect() | Find and remove the early output, or use ob_start() as a temporary fix |
Preventing It Going Forward
A few habits keep this from coming back:
- Don't close PHP tags at the end of files that are pure PHP —
wp-config.php,functions.php, custom plugin files. WordPress core follows this rule for a reason. - Set your code editor to save files as UTF-8 without a BOM by default, not just for WordPress files.
- Keep
WP_DEBUG_LOGenabled on a staging copy of the site so warnings land in a log file instead of surprising a visitor on the live one. - After editing
wp-config.phpdirectly in File Manager, scroll to the very top and bottom before saving — it's the fastest way to catch a stray character.
Frequently Asked Questions
Is this warning dangerous, or can I just ignore it?
The warning itself won't damage your site or database. The problem is what it blocks: if it's stopping a redirect or a cookie from being set, features like login, checkout, or settings pages can misbehave even though the page technically "loads." It's worth fixing rather than ignoring.
Why does the error only show up on some pages and not others?
Because it only triggers when PHP actually tries to send a header after output has already started. A page that never redirects or sets a cookie won't trigger it, even if the same stray whitespace is technically present on every request.
I fixed wp-config.php but the error is still there. Why?
There can be more than one offending file. Re-run the request with WP_DEBUG_LOG turned on and check the new "output started at" line — it may now point somewhere else, like a theme file or a different active plugin.
Can a caching plugin cause this?
Yes, indirectly. Some caching plugins write debug comments or buffer-management code near the top of wp-config.php during setup. If the warning appeared right after installing or configuring a cache plugin, check what it added to that file first.
Does upgrading my PHP version cause this?
Not directly — this is a PHP output-buffering behavior, not a version-specific bug. It can look tied to a PHP upgrade if the upgrade also reset error reporting settings and made a warning visible that was already happening silently before.
