Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when nextjs tries to warn about non-plain object prop binding - Error: Cannot convert a Symbol value to a string #61966

Open
jon-ressio opened this issue Feb 12, 2024 · 4 comments
Labels
bug Issue was opened via the bug report template.

Comments

@jon-ressio
Copy link

jon-ressio commented Feb 12, 2024

Link to the code that reproduces this issue

https://github.com/jon-ressio/vercel-prop-warn-error

To Reproduce

  1. Start the application in dev mode
  2. Load the app in a browser
  3. See Error page

Note: This only happens when running under next dev, next build && next start works as expected

Current vs. Expected behavior

From page.tsx, <Thing> is included twice. The first instance causes Warning: Only plain objects can be passed to Client Components from Server Components. URL objects are not supported. to show up in the server console, but the second instance causes the page to error out with: TypeError: Cannot convert a Symbol value to a string

The as={SomeLink} prop seems to not be handled by the Next/react warning, so the code trying to generate/show the warning causes a runtime error.

Expected: To render the same warning for the second <Thing> as done for the first.

Provide environment information

NOTE: I did test this in 4.1.1-canary.50 and the issue still exists

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 ZEN SMP PREEMPT_DYNAMIC Mon, 05 Feb 2024 22:07:37 +0000
Binaries:
  Node: 18.19.0
  npm: 10.2.3
  Yarn: 1.22.21
  pnpm: 8.15.1
Relevant Packages:
  next: 14.1.0
  eslint-config-next: 14.0.4
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.2.2
Next.js Config:
  output: N/A


warn  - Latest canary version not detected, detected: "14.1.0", newest: "14.1.1-canary.50".
        Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
        Read more - https://nextjs.org/docs/messages/opening-an-issue

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

App Router

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

next dev (local)

Additional context

Issue does not exist in 13.5.6, does exist in 14.0.0

@jon-ressio jon-ressio added the bug Issue was opened via the bug report template. label Feb 12, 2024
@jon-ressio jon-ressio changed the title Error when trying to warn about non-plain object prop binding - Error: Cannot convert a Symbol value to a string Error when nextjs tries to warn about non-plain object prop binding - Error: Cannot convert a Symbol value to a string Feb 12, 2024
@icyJoseph
Copy link
Contributor

icyJoseph commented Feb 13, 2024

Hi,

The problem here is that you have to consider that, there's a network boundary when you do:

export default function Home() {
  return (
    <main>
        {/* other stuff */}
        <Thing href={new URL("https://example.com")}>WARN, BUT RENDERS</Thing>
        <Thing as={SomeLink} href={new URL("https://example.com")}>
          ERROR, BREAKS PAGE TRYING TO LOG WARNING?
        </Thing>
        {/* other stuff */}
    </main>
  );
}

Precisely here: Thing href={new URL("https://example.com") and Thing as={SomeLink} href={new URL("https://example.com")}, so that means that as and href have to be serialized to be send from the server to the client.

Not everything can be serialized, and deserialized for that matter. In this case, serialize means to be able to transform this data structure into another data structure that can be sent over HTTP from the server to the client, and which the client can then transform back to the original data structure. The transformation can be no transformation at all.

The React Server Components lists a bunch of things that they can support as serializable data:

Notably URL is not listed, and it is not supported as serializable, however possible it might look like. I guess the .toString() method is being called here, and that's why it works, even though React cannot say that on the client there'll be a URL object to work with.

However, this line is important:

  • Client or Server Component elements (JSX)

In your example, you are passing a Client Component to the as prop, which is essentially passing a function. A React Component is a function that returns a React Element.

And functions are not supported (unless Server Actions):

However you could do:

        <Thing
          as={<SomeLink href="http://example.com" />}
          href={new URL('https://example.com')}
        >
          ERROR, BREAKS PAGE TRYING TO LOG WARNING?
        </Thing>

Notice that I am passing <SomeLink href="" />, which is a React element (JSX), and that is allowed.

Then you'd just need to update your type in the Thing as type definition to take an Element instead, just like Suspense's fallback does.

Here you go: https://stackblitz.com/edit/github-ct3nlz?file=src%2Fapp%2Fpage.tsx,src%2Fapp%2FThing.client.tsx,src%2Fapp%2FSomeLink.client.tsx

@jon-ressio
Copy link
Author

Completely agree, the code we have doesn't work and shouldn't.

The issue is that the code in next.js that tries to render the warning causes the page to error out instead of a warning to be shown on the next console/output.

I think I tracked this down and it may be upstream in react.

ReactFlightWebReference.js L216-227

Notice how all the other references to name have it wrapped in a String(name) call except the last one. I think it's just missing the String() call to ensure it can stringify name which is possibly/in-this-case a Symbol?

image

@icyJoseph
Copy link
Contributor

But the error is because you are passing a function, the as prop, that is the reason for the crash.

A function can't be serialized. You have to change it to a React Element, JSX, rather than a React Component, a function.

@sebmarkbage
Copy link
Contributor

sebmarkbage commented Feb 16, 2024

The as prop is fine because it's a reference to a client function. The issue is that it's trying to print the as prop as part of the error message to provide context.

Will be fixed by facebook/react#28355

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

3 participants