facebook/react · error · Error

321

321

Error message

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.

What it means

The classic 'Invalid hook call': hooks only work while React is rendering a function component, and the reconciler enforces it by swapping in a dispatcher (ContextOnlyDispatcher) whose hook methods throw. The error message itself lists the three root causes it almost always is: mismatched React/renderer versions, breaking the Rules of Hooks, or multiple React copies in one bundle.

Source

Thrown at packages/react-reconciler/src/ReactFiberHooks.js:446

      const componentName = getComponentNameFromFiber(currentlyRenderingFiber);
      if (!didWarnAboutAsyncClientComponent.has(componentName)) {
        didWarnAboutAsyncClientComponent.add(componentName);
        console.error(
          '%s is an async Client Component. ' +
            'Only Server Components can be async at the moment. This error is often caused by accidentally ' +
            "adding `'use client'` to a module that was originally written " +
            'for the server.',
          componentName === null
            ? 'An unknown Component'
            : `<${componentName}>`,
        );
      }
    }
  }
}

function throwInvalidHookError() {
  throw new Error(
    'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
      ' one of the following reasons:\n' +
      '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
      '2. You might be breaking the Rules of Hooks\n' +
      '3. You might have more than one copy of React in the same app\n' +
      'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.',
  );
}

function areHookInputsEqual(
  nextDeps: Array<mixed>,
  prevDeps: Array<mixed> | null,
): boolean {
  if (__DEV__) {
    if (ignorePreviousDependencies) {
      // Only true when this component is being hot reloaded.
      return false;
    }

View on GitHub (pinned to eafeac097b)

Solutions

  1. Run `npm ls react react-dom` (or pnpm why react) and eliminate duplicate copies; add bundler/alias resolution so only one react resolves.
  2. Align react and react-dom to the exact same version (never mix major/minor).
  3. Audit the stack trace: ensure every hook call is at the top level of a function component or custom hook — never in conditions, loops, class methods, callbacks, or module scope.
  4. Install/enable eslint-plugin-react-hooks to catch Rules-of-Hooks violations statically.

Example fix

// before: hook outside a component render
const [count, setCount] = useState(0); // module scope or plain function

// after: hook inside a function component
function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Defensive patterns

Strategy: validation

Validate before calling

// Boot-time duplicate/copy check: every React global must agree
import React from 'react';
import ReactDOM from 'react-dom';
if (React.version !== ReactDOM.version) {
  throw new Error(`react ${React.version} / react-dom ${ReactDOM.version} mismatch`);
}
// plus CI: `npm ls react react-dom` must resolve to exactly one version each

Type guard

// Narrow values before calling hook-like helpers: only call hooks inside component render
function isFunctionComponentInProgress() {
  // public approximation: hooks must run during render — enforce via eslint rule instead of runtime
  return false;
}

Try / catch

// Not for swallowing — for diagnosis: capture stack, check for duplicate react in node_modules
window.addEventListener('error', e => {
  if (/Invalid hook call/.test(e.message)) console.error(e.error.stack, React.version);
});

Prevention

When it happens

Trigger: Calling useState/useEffect/... from a class component, a plain function, an event handler body, or outside render entirely; or the hook runs in a component rendered by a different React copy than the one whose hook function you imported (npm dedupe failures, symlinked monorepos, bundler aliasing).

Common situations: Mismatched react/react-dom versions after partial upgrades; two react copies via transitive deps or duplicated peer dependencies in Yarn/pnpm workspaces; calling a custom hook from a non-component function; hooks behind early returns or inside conditions.

Related errors


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