Open charltoons opened 1 year ago
This comes from React, we just vendor it for use in the App Router https://github.com/facebook/react/blob/9c54b29b44d24f8f8090da9c7ebf569747a444df/packages/shared/ReactSerializationErrors.js#L28
is there an easy way to silence that warning? 😅
Edit: sadly will have to settle for
JSON.parse(JSON.stringify(data))
from https://github.com/vercel/next.js/issues/11993#issuecomment-617375501 for now
Having same issue for records coming from Mysql database
Can i deactivate this warning? I got many of it...
It's happing for me with files, which I can't stringify 😬
I can upload everything fine, but get this huge red warning.
const formData = new FormData();
formData.append("audioFile", input.audioFile[0] as File);
await upload(
formData,
);
Looks like I'm doing everything correctly too.
+1 for this.
seem like it can be resolved with JSON.parse(JSON.stringify(data))
but this is reduntant.
Passing mongo db objectId's also gives this error, stringifying it gives more errors and it becomes repetitive. I just wanted to know if this warning can create any huge errors?
you shoud before passing data to page for use data, convert to string and so to json data={JSON.parse(JSON.stringify(unit))}
I'm still getting this error. Can anyone help me out?
Am still getting this error. Any solution?
I started getting this issue using react query, I was trying to use the provider in the server component.
moving it into its own 'providers.tsx' and using "use client"; at the top solved this for me
It's happing for me with files, which I can't stringify 😬
I can upload everything fine, but get this huge red warning.
const formData = new FormData(); formData.append("audioFile", input.audioFile[0] as File); await upload( formData, );
Looks like I'm doing everything correctly too.
I am having the same problem? were you able to fix it?
I have the same issue since graphql
uses Object.create(null)
(repro).
I started getting this issue using react query, I was trying to use the provider in the server component.
moving it into its own 'providers.tsx' and using "use client"; at the top solved this for me
hey , were you able to fix it?
I am experiencing this issue however it's not just throwing a warning in my server, I am unable to carry out mutations.
I have commented out more than half the code, still can't seem to find the problem.
I started getting this issue using react query, I was trying to use the provider in the server component.
moving it into its own 'providers.tsx' and using "use client"; at the top solved this for me
issue also comes up for me - using nextjs 14.1 and react-query 5.22. Provider placement sadly does not change it, and serialization breaks types, as well as parsing special objects like dates.
App seems to be working fine, is there any way to silence the warning?
This problem is generated by the fact that you are passing a complex property from a server-side component to a client-side component, most likely at some level of the object there are classes or functions that are not easily serialized, so you need make the conversion manually before passing this property.
Example:
const getData = async () => AnyORM.find();
export const MyServerSideComponent = async () => {
const data = await getData();
return <MyClientSideComponent data={structuredClone(data)} />;
};
Doc: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
I ran into the same issue. I'm using libsql to fetch data from the database (Turso). I looked through the React code linked in the first response post above. It turns out you can't pass instances of classes; you can only pass plain objects. For me the issue was that libsql is adding 2 extra properties on top of the data queried, both of which they made non-enumerable. The React code actually goes through all the data you pass (here), goes through each property on each object, and checks if each property is enumerable. If it isn't, then you'll get the warning described in the OP.
I describe the issue in more detail in the Turso/libsql Discord here.
This issue only occurs in development. Not in prod!
Two workarounds have already been mentioned: JSON.parse(JSON.stringify(data))
and structuredClone(data)
. I don't like these, because they deep clone all of your data. If you do this for big chunks of data (which will probably happen a lot), it will result in a lot of overhead.
If your problem is also that your ORM/db client is adding non-enumerable properties, then all you need to do is spread the data into a new object: const newData = { ...data }
. So if you get an array of objects back, you can map over it:
const newData = data.map(d => ({ ...d }));
If the non-enumerated properties only exist at the top level and you have nested data of some kind, then you will save yourself a lot of computations. Spreads only copy the top level of the object, not deeper nested data. The other two workarounds do deep copies.
If you have non-enumerated properties on each level, then you're better off doing a deep copy with structuredClone(data)
.
I use Kysely in my apps, and Kysely accepts plugins that alter queries or results gotten from the db. Instead of doing spread calls everywhere I use my db client, I wrote a plugin that does this for me. I'm sure other ORMs/query builders provide similar functionality. Here's the plugin I wrote:
import { type KyselyPlugin } from 'kysely';
export const spreadDataInDevPlugin: KyselyPlugin = {
transformQuery: args => args.node,
transformResult: async args => {
// libsql adds some non-enumerable properties (length, and an index) to db responses.
// React checks all properties in objects that are passed down from server- to client components.
// To prevent devs from passing down non-trivial objects and possibly getting unexpected results,
// they display a warning when a property is non-enumerable.
// This only happens during development. See: https://github.com/vercel/next.js/issues/47447#issuecomment-2064362712
// In order to avoid that warning for data fetched using libsql, we use this plugin
// to spread the result, which copies over enumarable properties only.
// We load the plugin in development only to prevent unnecessary computations.
return { ...args.result, rows: args.result.rows.map(r => ({ ...r })) };
},
};
Then we use it like this in our Kysely client setup:
const plugins = env.NODE_ENV === 'development' ? [spreadDataInDevPlugin] : [];
export const db = new Kysely<Database>({
dialect: conn, // The dialect set up by yourself
plugins,
});
~This runs only in dev, and the overhead in prod is minimal (just the env check, and the extra overhead from having callbacks from the plugin).~ We only load the plugin in dev, which means there is no overhead in prod to work around this. The added benefit is we still get the warnings React provides us if we pass down data that does not come from our ORMs/query builders! The con here is that we do slightly different things to our data in dev compared to other envs, so beware of that!
Hope this helps someone out there!
Edit: Changed the code to only load the plugin in dev, instead of always loading it and doing the env check inside the plugin
`'use client' import { Input } from "./ui/input"; import { Label } from "./ui/label"; import { Textarea } from "./ui/textarea"; import { usePetContext } from "@/lib/hooks"; import { PetFormBtn } from "./pet_form_btn"; import { addPet, editPet } from "@/server_actions/actions"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { petFormSchem } from "@/lib/schemas";
export const PetForm = ({ actionType, checkFormOpen }: PetFormProps) => {
//get actionType handler form state manager
const { selectedPet } = usePetContext()
const { formState: { errors, isSubmitting }, register, trigger, getValues } = useForm<Omit<petType, "id">>(
{ resolver: zodResolver(petFormSchem) }
)
const data: Omit<petType, "id"> = getValues()
// "client action" for server action
async function submitForm() {
let responce = await trigger()
if (!responce) return null
if (actionType === "add") {
try {
const res = await addPet(JSON.parse(JSON.stringify(data).toString()))
res && checkFormOpen(false)
} catch (error) {
console.log(error);
alert(`${error}`)
// checkFormOpen(false)
}
}
if (actionType === "edit") {
try {
if (selectedPet) {
const res = await editPet(selectedPet?.id, JSON.parse(JSON.stringify(data)))
res && checkFormOpen(false)
}
} catch (error) {
console.log(error);
alert(`${error}`)
checkFormOpen(false)
}
}
}
return (
<form action={submitForm} className="flex flex-col">
<div className="space-y-4 ">
<div className="space-y-2">
<Label htmlFor="name">Name</Label>
<Input
id="name"
{...register("name", { required: "name is", maxLength: 20 })}
/>
{errors.name && <p className="text-red-700" >{errors.name.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="Owner Name">Owner Name</Label>
<Input
id="ownerName"
{...register("ownerName")}
/>
{errors.ownerName && <p className="text-red-700">{errors.ownerName.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="Image url">Image url</Label>
<Input
id="imageUrl"
{...register("imageUrl")}
/>
{errors.imageUrl && <p className="text-red-700">{errors.imageUrl.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="Age">Age</Label>
<Input
id="age"
{...register("age")}
/>
{errors.age && <p className="text-red-700">{errors.age.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="Notes">Notes</Label>
<Textarea id="notes"
{...register("notes")}
/>
{errors.notes && <p className="text-red-700">{errors.notes.message}</p>}
</div>
</div>
<PetFormBtn actionType={actionType} />
</form>
);
}
` tried solutions but still getting same warning any other solution ?
@waqas-on-github It seems unlikely to me that the warning is triggered because of the form. Your form seems to contain only strings and perhaps a number for your “age” field. I’ve also never had this problem with form actions.
My guess is the problem is triggered from the fetching of your data. It looks like you’re keeping the pet data in a context (selectedPet
)?
When passing data down from server components to client components, make sure to run {…obj}
on every object in the list. For example:
const data = await db.getAllPets();
return data.map((pet) => ({…pet}));
Or
const data = await db.getOnePet(id);
return {…data};
ORMs or db clients tend to modify each object by adding certain non-iterable properties, which aren’t allowed by React when passing data down to client components. Calling {…obj}
or in the worst case JSON.parse(JSON.stringify(obj))
will remove those properties and avoid the warning.
It's happing for me with files, which I can't stringify 😬
I can upload everything fine, but get this huge red warning.
const formData = new FormData(); formData.append("audioFile", input.audioFile[0] as File); await upload( formData, );
Looks like I'm doing everything correctly too.
Having same problem have you found a solution?
Verify canary release
Provide environment information
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true)
Link to the code that reproduces this issue
https://github.com/charltoons/next-rsc-null-prototype-warning
To Reproduce
Pass an object with a
null
prototype from a Server Component to a Client ComponentExample server component:
Example client component:
Describe the Bug
Observe in the server logs the following warning:
While this is only a warning and does not inhibit runtime behavior, large objects will print this warning for each object instance. We discovered this issue when trying to pass an extracted cache from an Apollo client (which uses null prototype) to a client component. In this case, it results in hundreds of lines of warning logs for each request.
I'm not sure if this a a Next.js bug or a React bug. The issue can be attributed to this function: https://github.com/vercel/next.js/blob/canary/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.browser.development.js#L1154
Expected Behavior
No warning is emitted since objects with
null
prototype are serializable.Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
Vercel (the issue appears during local dev)