facebook/react · error · Error

538

538

Error message

Cannot use state or effect Hooks in renderToHTML because this component will never be hydrated.

What it means

When Fizz runs with a config whose supportsClientAPIs is false (static HTML generation such as renderToHTML whose output is never hydrated), the hook dispatcher replaces every stateful or effectful hook with clientHookNotSupported. useState, useReducer, useRef, useEffect, useLayoutEffect, useInsertionEffect, useImperativeHandle, useDeferredValue, useTransition, and useSyncExternalStore all throw error code 538 because the HTML will never hydrate and React refuses to allocate state.

Source

Thrown at packages/react-server/src/ReactFizzHooks.js:877

function unsupportedRefresh() {
  throw new Error('Cache cannot be refreshed during server rendering.');
}

function useCacheRefresh(): <T>(?() => T, ?T) => void {
  return unsupportedRefresh;
}

function useMemoCache(size: number): Array<mixed> {
  const data = new Array<any>(size);
  for (let i = 0; i < size; i++) {
    data[i] = REACT_MEMO_CACHE_SENTINEL;
  }
  return data;
}

function clientHookNotSupported() {
  throw new Error(
    'Cannot use state or effect Hooks in renderToHTML because ' +
      'this component will never be hydrated.',
  );
}

// $FlowFixMe[constant-condition]
export const HooksDispatcher: Dispatcher = supportsClientAPIs
  ? {
      readContext,
      use,
      useContext,
      useMemo,
      useReducer,
      useRef,
      useState,
      useInsertionEffect: noop,
      useLayoutEffect: noop,
      useCallback,

View on GitHub (pinned to eafeac097b)

Solutions

  1. Remove stateful and effect hooks from components rendered to static HTML
  2. Split the component: render presentational output statically and mount interactive parts as client components
  3. If the output will actually be hydrated, switch to a hydration-capable API (renderToPipeableStream / renderToReadableStream)

Example fix

// before (rendered with a static, never-hydrated renderToHTML-style API)
function Counter() {
  const [n, setN] = useState(0); // throws: output never hydrates
  return <button>{n}</button>;
}

// after
function CounterView({label}) {
  return <span>{label}</span>; // pure output, safe for static HTML
}
// mount the interactive version as a client component in the hydrated app
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: Rendering a component that calls any stateful or effect hook through a static HTML API whose output is not hydrated — renderToStaticMarkup-style or renderToHTML static generation.

Common situations: Generating static pages or emails with components that also run in the hydrated app; shared component libraries that assume useState always works; moving a pipeline from renderToPipeableStream to a static renderer.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/7012cceb2bbc5d39. Report an issue: GitHub.