/ โ† JavaScript Checker Fixes / React and Next.js
In this guide
  1. Why React errors look different
  2. Common React and Next.js errors and where they come from
  3. Fixing hydration mismatches properly
  4. Browser-only code and server rendering
  5. Environment variables that vanish in the browser
  6. The fix, step by step
  7. Error boundaries in practice
  8. Edge cases
  9. Questions and answers

Why React errors look different

A production React build strips out its long explanatory messages to save space. Instead of a sentence, you get something like Minified React error #418; visit https://react.dev/errors/418 for the full message. The number is a code for the full text, and the link explains it. The development build, which you run locally, prints the complete message, the component that caused it and a component stack showing where it sits in the tree.

React also changes what happens after an error. In a plain script, an uncaught error stops one task and the rest of the page carries on. In React, an error thrown while rendering a component, and not caught by an error boundary, removes the entire component tree from the screen. On a site where React renders the whole page, that means a white screen, both for visitors and for any crawler that renders the page.

Frameworks such as Next.js add a third place for errors to happen: the server. Code runs once on the server to produce HTML, then again in the browser to hydrate it. An error can appear in either place, or come from the two runs disagreeing, and each needs a different fix.

Common React and Next.js errors and where they come from

What you seeWhere it happensUsual cause
Hydration failed, or text content does not match server-rendered HTML (minified codes such as #418 and #423)Browser, during hydrationDates, random numbers, window checks, locale formatting or invalid HTML nesting producing different markup on each side.
window is not defined or document is not definedServer, during rendering or buildBrowser-only code at the top of a module or in the render body, or a library that touches the browser on import.
A variable is undefined only in the browserBrowserAn environment variable without the NEXT_PUBLIC_ prefix, which Next.js never sends to client code.
Blank white page with one error in the consoleBrowserA render error with no error boundary above it.
Each child in a list should have a unique "key" propDevelopment onlyLists rendered without stable keys. Not shown in production, but can cause wrong items to update.
Hooks errors such as rendered more hooks than during the previous renderBrowser or serverA hook called inside a condition, loop or early return, or two copies of React in the bundle.
You're importing a component that needs useStateBuild, Next.js App RouterA server component using hooks or browser events without the 'use client' directive.
๐Ÿ’ก Before chasing any hydration error, open the page in a private window with extensions switched off. Browser extensions that edit the page, such as grammar checkers, password managers and translation tools, add attributes or elements before React hydrates, and React then reports a mismatch that your code did not cause.

Fixing hydration mismatches properly

Hydration expects the browser's first render to produce exactly the HTML the server sent. Anything that can differ between the two runs will break that. The fix is always to make the first render deterministic, then change anything browser-specific afterwards.

Dates, times and random values

A server in one time zone and a visitor in another will format the same date differently. Math.random() and Date.now() give different answers each time. Either format dates on the server with a fixed time zone and pass the finished string down, or render a neutral placeholder first and fill in the local value after mounting.

'use client';
import { useEffect, useState } from 'react';

export function LocalTime({ iso }) {
  const [text, setText] = useState(null);
  useEffect(() => {
    setText(new Date(iso).toLocaleTimeString('en-GB'));
  }, [iso]);
  return <time dateTime={iso}>{text ?? 'Today'}</time>;
}

Checks for the browser during render

Code such as typeof window !== 'undefined' ? A : B inside the render body produces B on the server and A in the browser. Move the check into an effect, as above, so both sides render B first.

Invalid HTML nesting

Browsers repair some invalid HTML as they parse it. A <div> inside a <p>, a link inside a link, or a table without its body element will be rearranged by the browser, so the structure React finds no longer matches. The development build names the offending elements; fix the markup.

Using suppressHydrationWarning

The suppressHydrationWarning prop silences the warning for one element's own text or attributes, one level deep. It is meant for values that are expected to differ, such as a timestamp. It does not fix anything, and using it on a wrapper to hide wider mismatches leaves the underlying problem in place.

Browser-only code and server rendering

Anything that uses window, document, localStorage or navigator only exists in the browser. When that code runs during server rendering or a static build, it throws. Three patterns cover almost every case:

'use client';
import dynamic from 'next/dynamic';

const StoreMap = dynamic(() => import('./StoreMap'), {
  ssr: false,
  loading: () => <p>Loading mapโ€ฆ</p>,
});
โš ๏ธ Only skip server rendering for widgets that genuinely cannot run there. If the component holds text, prices or links, skipping server rendering removes them from the HTML crawlers receive. Guard the browser-only part instead.

Environment variables that vanish in the browser

Next.js only includes environment variables in client-side code when their names start with NEXT_PUBLIC_. Everything else stays on the server, which is deliberate: it keeps secrets such as API keys out of the browser. A component that reads process.env.API_URL will work during server rendering and get undefined in the browser, which often leads to a failed request to an address like undefined/products.

Vite-based React projects follow the same idea with a VITE_ prefix and import.meta.env; Create React App used REACT_APP_.

The fix, step by step

Step 1

Reproduce the error in a development build

Take the errors the JavaScript Checker captured and note the page and message for each. Run the site locally with the development server, open the same page in a private window with extensions off, and reproduce the error. The development build prints the full message, the component name and a component stack, which turns a vague production code into a named file and line you can open.

Step 2

Decode minified React error codes

If you cannot reproduce it locally, open the link in the production message, which goes to the React errors page for that code and shows the full text with the values filled in. Enable production source maps or upload them to your error monitoring service so the stack points at your components. Then check the build logs and server logs, since some errors happen on the server first.

Step 3

Make server and browser render the same markup

For each hydration error, find the value that differs between the two renders. Format dates on the server with a fixed time zone or set them after mounting, move random values and window checks into effects, and fix invalid nesting such as a block element inside a paragraph. Use suppressHydrationWarning only on a single element whose text is expected to differ, such as a timestamp.

Step 4

Keep browser-only code out of server rendering

Search for window, document, localStorage and navigator outside effects and event handlers, and move each use inside them. Load libraries that touch the browser on import with a dynamic import or next/dynamic from a client component. Add 'use client' only to the components that need hooks or browser events, not to whole pages, so text, prices and links stay in the server-rendered HTML that crawlers receive.

Step 5

Expose client environment variables correctly

List every environment variable read in client components and check its name. Values the browser needs must start with NEXT_PUBLIC_ in Next.js or VITE_ in Vite, and must be referenced by their full name. Keep secret keys unprefixed and reach them through a server route. Rebuild and redeploy after changing any public value, because it is written into the bundle at build time.

Step 6

Contain failures with error boundaries

Add an error boundary around each independent part of the page, such as reviews, recommendations, a map or a chat widget, so one failing component shows a small fallback instead of blanking the page. In the Next.js App Router, add error.js files to route segments and a global-error.js at the root. Report caught errors to your monitoring service from the boundary.

Step 7

Ship and verify a production build

Deploy, then open the live site with the React Developer Tools extension installed and confirm it reports a production build rather than development. Re-run the JavaScript Checker on each affected template, check the console is clear of hydration and render errors, and compare the rendered page with the raw HTML to make sure content you moved to the client did not disappear.

Error boundaries in practice

An error boundary is a component that catches render errors in the components below it and shows a fallback. React still requires a class component to write one yourself, though many projects use the small react-error-boundary package instead. Next.js App Router projects get boundaries per route segment by adding an error.js file, which must be a client component.

// app/products/[slug]/error.js
'use client';

export default function ProductError({ error, reset }) {
  return (
    <div role="alert">
      <p>Sorry, this part of the page could not load.</p>
      {/* A "Try again" button whose click handler calls reset() */}
    </div>
  );
}

The reset function asks Next.js to render the segment again, so wire it to a button's click handler to give visitors a retry. Boundaries have limits worth knowing. They catch errors during rendering, in lifecycle methods and in constructors below them. They do not catch errors in event handlers, in asynchronous code such as a timer or a fetch callback, or in the boundary itself. Handle those with ordinary try and catch, and set state so the next render can show a message.

Where you place boundaries decides what visitors lose. One boundary around the whole app turns a white screen into a friendly error page, which is better but still loses everything. Smaller boundaries around optional sections, such as reviews or related products, let the main content and the buy button survive when a secondary widget fails.

Edge cases

Questions and answers

1. What does Minified React error 418 mean?

Production React replaces its full error messages with numbered codes to save space, and each message includes a link to the React errors page that shows the full text. Code 418 is one of the hydration errors, meaning the HTML the server sent did not match what React rendered in the browser. Follow the link for the exact wording, then run the page in development mode, where React names the component and element that differed.

2. Why does my React site show a blank white page?

Since React 16, an error thrown while rendering a component that is not caught by an error boundary removes the whole component tree from the screen. If React renders the entire page, visitors and crawlers see nothing. Open the console to find the error, fix the component, and add error boundaries around independent sections so that a failure in one widget shows a small fallback message instead of emptying the page.

3. How do I fix window is not defined in Next.js?

The code is using a browser object while running on the server, during server rendering or a static build. Move any use of window, document or localStorage into a useEffect hook or an event handler, both of which only run in the browser. If a library touches the browser as soon as it is imported, load it with a dynamic import inside an effect or with next/dynamic and the ssr option switched off, from a client component.

4. Is suppressHydrationWarning a safe fix?

Only for the narrow case it was designed for: a single element whose own text or attribute is expected to differ between server and browser, such as a timestamp. It works one level deep and hides the warning without changing what renders. Using it on a wrapper to silence wider mismatches leaves the underlying problem, which can still cause React to re-render parts of the page and discard the server HTML there.

5. Why is my environment variable undefined in the browser?

Next.js only includes variables whose names start with NEXT_PUBLIC_ in client-side code, and it writes their values into the JavaScript at build time. A variable without the prefix exists on the server but is undefined in the browser. Rename values the browser genuinely needs, never secret keys, reference them by their full name, and rebuild after any change, because updating the value in your hosting dashboard alone does not alter the existing bundle.

6. Do hydration errors affect SEO?

The server-rendered HTML is still sent and can still be indexed, so a hydration warning on its own does not remove content. The risks are indirect: React may re-render the affected part of the page in the browser, which costs time and can shift layout, and if a hydration problem escalates into a render error without an error boundary, the page can go blank for any crawler that renders it. Fixing the mismatch removes both risks.

7. How can I tell if my live site is running a development build?

Install the React Developer Tools browser extension and visit the site. Its icon indicates whether the page uses a development or production build, and development builds are flagged clearly. Other signs are full, unminified React warnings in the console and much larger script files. Development builds are slower and should never be deployed, so check your build command, confirm your hosting sets the production environment, and look again after any change to the deployment pipeline.

Check your React pages for errors

The JavaScript Checker loads each page in headless Chromium, captures console errors and warnings, measures bundle size and execution time, and compares the rendered page with what a crawler receives.

Open JavaScript Checker Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All JavaScript Checker Fixes  ·  Fixing Console Errors at Page Load  ·  Next.js and Nuxt Web Vitals  ·  JavaScript That Crawlers Cannot Render  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.