Conoce a "Headers already sent": tu nuevo enemigo (y amigo)
\n\nSi alguna vez has programado en PHP, seguro te has topado con este error. Aparece de repente, justo en el peor momento — cuando ya casi terminas tu script. El mensaje es aterrador, rojo, y parece que todo el código se rompió. Pero en realidad, es uno de los errores más útiles de PHP. Te enseña a trabajar correctamente con el protocolo HTTP.
\n\nEn este tutorial, analizaremos por qué ocurre el error Headers already sent, cómo diagnosticarlo y, lo más importante, cómo solucionarlo de una vez por todas. No solo copiaremos una respuesta de Stack Overflow — entenderemos la esencia. ¡Allá vamos!
¿Qué son los encabezados HTTP y por qué PHP se queja de ellos?
\n\nAntes de curar, hay que entender la anatomía. Cuando PHP envía una respuesta al navegador, lo hace en dos etapas:
\n\n- \n
- Primero — los encabezados (headers). Esta es información técnica: tipo de contenido (
Content-Type), codificación, cookies, estado de la respuesta (200 OK, 404 Not Found). \n - Después — el cuerpo de la respuesta (body). Esto es el HTML, texto, JSON — lo que ve el usuario. \n
El problema es que PHP no puede enviar encabezados después de haber comenzado a enviar el cuerpo. Si intentas llamar a header() después de haber mostrado aunque sea un solo carácter (incluso un espacio), PHP lanzará el error:
Warning: Cannot modify header information - headers already sent by (output started at /ruta/al/archivo.php:12)\n\nEsa es toda la magia. El error no es fatal — solo advierte que tu header() no funcionó. Pero las consecuencias pueden ser graves: la redirección no se ejecutará, la cookie no se establecerá, la respuesta JSON se romperá.
Las 5 causas principales de este error
\n\nAnalicemos los escenarios más comunes. ¿Te identificas con alguno?
\n\n1. Espacio o línea en blanco antes de <?php
\n\nEsto es un clásico. Abres el archivo y antes de la etiqueta de apertura <?php hay un espacio, una línea en blanco o un carácter BOM (Byte Order Mark). PHP interpreta ese carácter como parte de la salida — y comienza el problema.
// ❌ Error: espacio antes de <?php\n <?php\nheader('Location: /nueva-pagina.php');\n?>\n\n// ✅ Correcto: ningún carácter antes de <?php\n<?php\nheader('Location: /nueva-pagina.php');\n?>\n\n2. Salida con echo o print antes de header()
\n\nUn error lógico pero común entre principiantes: primero mostrar algo y luego intentar redirigir al usuario.
\n\n<?php\necho "¡Hola, mundo!";\nheader('Location: /gracias.php'); // ❌ Error: ya hubo salida\n?>\n\n3. Código HTML antes del bloque PHP
\n\nEl archivo puede tener código mixto: primero marcado HTML, luego lógica PHP con header().
<!DOCTYPE html>\n<html>\n<head>\n <title>Mi sitio</title>\n</head>\n<body>\n<?php\nheader('Location: /login.php'); // ❌ Error: el HTML ya se envió\n?>\n</body>\n</html>\n\n4. Errores de PHP y funciones como var_dump()
\n\nEl script puede mostrar advertencias o información de depuración antes de llamar a header(). Por ejemplo, si tienes display_errors activado y PHP muestra un warning.
<?php\nvar_dump($alguna_variable); // Salida de datos\nheader('Content-Type: application/json'); // ❌ Error\n?>\n\n5. Caracteres invisibles en archivos incluidos (include/require)
\n\nIncluyes un archivo con include o require, y al final de ese archivo hay una línea en blanco extra o un espacio después del cierre ?>.
// config.php\n<?php\n$db_host = 'localhost';\n?>\n // ← ¡Este espacio después de ?> lo rompe todo!\n\nCómo encontrar el origen del problema: diagnóstico paso a paso
\n\nLo más importante: el error siempre indica dónde comenzó la salida. Lee el mensaje con atención