Skip to content

cloneElement in client component not working in production builds in some circumstances #82527

@Scrumplex

Description

@Scrumplex

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/n9rftd

To Reproduce

  1. <Suspense><ServerComponent> <ClientComponentDoingClone> <OtherClientComponent /> </ClientComponentDoingClone> <ServerComponent/><Suspense/>
  2. Create production build next build
  3. Start production build next start

Current vs. Expected behavior

Current behavior (since 15.4.1):

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

The Component doing cloneElement gets the following value for children which then causes the error:

{
  '$$typeof': Symbol(react.lazy),
  _payload: Promise { status: 'pending', value: null, reason: null },
  _init: [Function: P]
}

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
  Available memory (MB): 4102
  Available CPU cores: 2
Binaries:
  Node: 20.12.1
  npm: 10.5.0
  Yarn: 1.22.19
  pnpm: 8.15.6
Relevant Packages:
  next: 15.4.6 // Latest available version is detected (15.4.6).
  eslint-config-next: N/A
  react: 19.1.1
  react-dom: 19.1.1
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

React

Which stage(s) are affected? (Select all that apply)

Other (Deployed), next start (local)

Additional context

See #81876

This seems to be some kind of optimization around suspense boundaries, as it only occurs in production build and only after a certain amount of DOM elements (or React components??)

Some takeaways from my repro above:

  • This issue only occurs, if I have a <Suspense> boundary, containing a server component (be it sync or async) that in turn has a client component that does cloneElement on another client component.
  • Additionally, this only appears after a certain amount of components. In my production app, it takes four table rows to trigger this. In my repro example, it takes over 50.
  • This exclusively happens with production builds.
  • When this issue does NOT appear, children.'$$typeof' is Symbol(react.transitional.element), whereas when this issue happens it is Symbol(react.lazy)

Metadata

Metadata

Assignees

No one assigned

    Labels

    ReactRelated to React.

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions