{"record":{"id":"abf95bb593a9bba7","repo":"facebook/react","slug":"306","errorCode":"306","errorMessage":"Element type is invalid. Received a promise that resolves to: ${loggedComponent}. Lazy element type must resolve to a class or function.${hint}","messagePattern":"Element type is invalid\\. Received a promise that resolves to: (.+?)\\. Lazy element type must resolve to a class or function\\.(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-reconciler/src/ReactFiberBeginWork.js","lineNumber":2203,"sourceCode":"  let hint = '';\n  if (__DEV__) {\n    if (\n      // $FlowFixMe[invalid-compare]\n      Component !== null &&\n      typeof Component === 'object' &&\n      // $FlowFixMe[invalid-compare]\n      Component.$$typeof === REACT_LAZY_TYPE\n    ) {\n      hint = ' Did you wrap a component in React.lazy() more than once?';\n    }\n  }\n\n  const loggedComponent = getComponentNameFromType(Component) || Component;\n\n  // This message intentionally doesn't mention ForwardRef or MemoComponent\n  // because the fact that it's a separate type of work is an\n  // implementation detail.\n  throw new Error(\n    `Element type is invalid. Received a promise that resolves to: ${loggedComponent}. ` +\n      `Lazy element type must resolve to a class or function.${hint}`,\n  );\n}\n\nfunction mountIncompleteClassComponent(\n  _current: null | Fiber,\n  workInProgress: Fiber,\n  Component: any,\n  nextProps: any,\n  renderLanes: Lanes,\n) {\n  resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress);\n\n  // Promote the fiber to a class and try rendering again.\n  workInProgress.tag = ClassComponent;\n\n  // The rest of this function is a fork of `updateClassComponent`","sourceCodeStart":2185,"sourceCodeEnd":2221,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-reconciler/src/ReactFiberBeginWork.js#L2185-L2221","documentation":"mountIndeterminateComponent() re-dispatches a fiber after a React.lazy() promise settles. The resolved value must be a function component, class, forwardRef, memo, or context; anything else falls through to this throw, which prints what the promise actually resolved to. The dominant cause is a dynamic import whose module does not export a component as its default export.","triggerScenarios":"lazy(() => import('./Mod')) where './Mod' has only named exports; the default export is a plain object, constant, or hook; re-exporting one lazy component through another lazy() (React appends the hint 'Did you wrap a component in React.lazy() more than once?'); passing a non-component module (JSON, CSS) to lazy().","commonSituations":"Refactoring to named exports and forgetting the lazy wrapper; barrel files re-exporting through React.lazy; default-exporting a config object where a component was expected; test mocks resolving to {default: {}}; bundler default-export interop changes.","solutions":["Open the module named in the error and make its default export a function or class component","For named-only exports, map it: lazy(() => import('./Mod').then(m => ({default: m.NamedComp})))","Remove nested lazy() wrappers - pass the import() directly to React.lazy","Fix test mocks to resolve to {default: () => <div />}"],"exampleFix":"// before - Mod has no default export\nconst Panel = lazy(() => import('./Mod'));\n\n// after - add a default export\nexport default function Mod() { /* ... */ }\n\n// or map a named export\nconst Panel = lazy(() => import('./Mod').then(m => ({default: m.NamedPanel})));","handlingStrategy":"type-guard","validationCode":"const loadPanel = async () => {\n  const mod = await import('./Mod');\n  if (!isComponentType(mod.default)) {\n    throw new Error(`./Mod default export is ${typeof mod.default}, expected a component`);\n  }\n  return {default: mod.default};\n};\nconst Panel = lazy(loadPanel);","typeGuard":"function isComponentType(x) {\n  if (typeof x === 'function') return true;\n  return typeof x === 'object' && x !== null && typeof x.$$typeof === 'symbol';\n}","tryCatchPattern":"Wrap lazy components in an ErrorBoundary with a fallback UI; reset the boundary on route change so a fixed deployment's chunk is loaded fresh instead of a cached rejected promise.","preventionTips":["Default-export every lazy-loaded route or component","Never wrap the output of React.lazy() in React.lazy() again","Keep test mocks shaped as {default: () => <div />}"],"tags":["react-lazy","code-splitting","dynamic-import","element-type"],"backgroundTag":"invalid-element-type","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}