Cómo arreglar Minified React error #425 (error de hidratación)
Respuesta rápida
El error #425 de React —"Text content does not match server-rendered HTML"— es un error de hidratación: el servidor renderizó un valor y el navegador otro distinto, así que React descarta el HTML del servidor para ese subárbol. El arreglo depende de por qué difieren:
- El valor difiere de forma legítima (una fecha, una hora) → añade
suppressHydrationWarning(Arreglo 1). - El valor solo existe en el navegador (
window,localStorage) → renderízalo tras el montaje (Arreglo 2). - El componente entero es solo-cliente → cárgalo con
next/dynamicyssr: false(Arreglo 3). - Tu HTML es inválido (un
<div>dentro de un<p>) → corrige el anidamiento (Arreglo 4).
El error completo en producción es: Uncaught Error: Minified React error visit https://reactjs.org/docs/error-decoder.html?invariant=425 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
Qué significa realmente "Minified React error #425"
En una build de producción React envía los mensajes de error minificados para mantener el bundle pequeño, así que en vez de una frase recibes un número y un enlace descodificador (invariant=425). El #425 descodifica a "Text content does not match server-rendered HTML".
Eso solo ocurre con renderizado en servidor (Next.js, Remix, renderToString): React renderiza el HTML una vez en el servidor, lo envía al navegador y luego hidrata —reutiliza ese HTML y solo engancha los manejadores de eventos, esperando que el primer render del cliente produzca exactamente la misma salida—. Cuando un trozo de texto sale distinto, la hidratación de ese subárbol falla y aparece el #425.
Como el mensaje está minificado, el paso de depuración más útil es reproducirlo en una build de desarrollo: ahí React imprime el mensaje completo y señala el elemento exacto, lo que convierte las conjeturas en un arreglo de una línea (ver "Cómo ver el error real" más abajo).
Por qué ocurren los errores de hidratación
Todo #425 se reduce a salida del servidor ≠ primera salida del cliente. Los sospechosos habituales:
| Causa | Por qué difiere |
|---|---|
new Date() / toLocaleString | El reloj/zona del servidor ≠ el reloj/zona del navegador |
Math.random(), Date.now(), uuid() | Un valor nuevo en cada render, servidor y cliente nunca coinciden |
| Formato de número/moneda por locale | El locale del servidor ≠ el del navegador del usuario |
window, localStorage, navigator | Indefinidos en el servidor, presentes en el navegador |
| Anidamiento HTML inválido | El navegador "arregla" tu HTML, así que el DOM ≠ lo que renderizó React |
| Extensiones del navegador | Modifican el DOM antes de que React hidrate |

El ejemplo de abajo es el caso clásico: un reloj en vivo.
El código que provocaba el error
El servidor renderiza la hora para su reloj y zona horaria; un segundo después el navegador renderiza la suya —el texto difiere y React lanza el #425—.
Arreglo 1 — suppressHydrationWarning para diferencias de texto legítimas
Cuando la diferencia es real y esperada (un reloj, un "hace 2 minutos"), dile a React que la acepte en ese elemento con suppressHydrationWarning. Solo silencia una diferencia de texto un nivel de profundidad: es un bisturí, no una manta, así que no lo esparzas por todas partes.
Arreglo 2 — Renderiza los valores del navegador tras el montaje
Si el valor sencillamente no existe en el servidor (window, localStorage, matchMedia), renderiza primero un marcador estable y sustitúyelo por el valor real después de que el componente se monte. El servidor y el primer render del cliente ya coinciden, y el valor del navegador aparece en el siguiente pintado.
Arreglo 3 — Carga los componentes solo-cliente con next/dynamic
Cuando un componente entero no puede renderizarse nunca en el servidor (una gráfica que lee window, un mapa, un editor), sáltate el SSR por completo en vez de proteger cada línea:
Arreglo 4 — Corrige el anidamiento HTML inválido
Este sorprende porque no hay ninguna fecha ni valor aleatorio a la vista. Si anidas un elemento de bloque dentro de un <p> (o un <a> dentro de un <a>, o un <div> dentro de una <table> sin <tbody>), el navegador repara el HTML en silencio al parsearlo. React hidrata entonces contra un DOM que ya no coincide con lo que renderizó, y aparece el #425. No hay atributo que silencie esto: haz que el HTML sea válido (un <p> solo puede contener contenido en línea).
Cómo ver el error real
Nunca depures el #425 desde el número minificado. Reprodúcelo donde React sí te habla:
- Next.js: ejecuta
next dev—el desarrollo nunca está minificado—. - Build de producción en local:
next build && next start, pero lee el mensaje en la consola del navegador, donde React imprime el texto completo y un diff del elemento que no cuadra.
React registra algo como "Warning: Text content did not match. Server: '14:32' Client: '14:33'", señalando el nodo exacto. A partir de ahí la causa suele ser obvia.
#418, #422, #423, #425 — la familia de errores de hidratación
Si tus búsquedas trajeron números vecinos, son el mismo problema visto desde ángulos distintos:
| Error | Significado |
|---|---|
| #418 | La hidratación falló porque la UI inicial difería |
| #422 | La hidratación terminó pero contenía discrepancias |
| #423 | Error al hidratar; el árbol cayó a renderizado en cliente |
| #425 | El contenido de texto no coincide con el HTML del servidor |
El arreglo es siempre la misma disciplina: ejecuta una build de desarrollo, encuentra el valor que difiere entre servidor y cliente, y reconcílialo con uno de los cuatro arreglos de arriba.
Puedes leer más sobre el atributo en la documentación de React.
