Objects are not valid as a React child (found: object with keys)
Filed under Next.js & React errors
A { } expression in your JSX is rendering a whole object (or a Date) instead of one text field from it.
Fastest route
Give your AI this prompt
Copy it, replace the bracketed part with your error, and send it.
Preview the prompt
My React app crashes with: "Objects are not valid as a React child (found: object with keys {...})".
The component that crashes is: [paste component code] and the data it renders comes from: [paste a sample of the data or the API response, or describe where it comes from].
Please: 1) use the keys named in the error to identify exactly which object is being rendered whole, 2) change that expression to print the specific text field I want on screen, walking into nested objects if needed, 3) if the value is a list, rewrite the render with .map() and a stable key; if it is a Date or timestamp, format it into text, 4) check the rest of the component for other expressions rendering objects the same way.
Constraints: do not paper over it with JSON.stringify in the final code, do not change my layout or styling, make one change at a time, and tell me which object caused it before you change code.Fix it yourself
Follow the repair
- Use the keys in the error as a fingerprint. Read the end of the error message: it lists the offending object's keys, something like
{title, body, created_at}. Those keys belong to one specific object in your data. Search your components for the place where an object with exactly those fields is placed inside curly braces as a whole — that expression is your crash, and it is usually within a few lines of where those fields are used correctly elsewhere. - Print a field, not the object. Change the expression from the whole record to the text you actually want on screen:
If the value you want lives one level down — an author's name inside an// Crashes — post is a whole object: <p>{post}</p> // Works — print the field you meant to show: <p>{post.title}</p>authorobject is the classic case — walk the extra step and print{post.author.name}. Keep going down until what lands in the braces is a string or a number. - If it is a list of objects, map it. An array of records cannot be printed either; it has to be turned into elements, one per item, with a stable
keyon the outer element so React can track them:
This is the most common version of the crash: the code renders{posts.map((post) => ( <article key={post.id}> <h2>{post.title}</h2> <p>{post.excerpt}</p> </article> ))}{post}somewhere it should have mapped, or prints the whole API response instead of the array inside it. - Format Dates instead of printing them. A JavaScript
Dateis an object, so dropping one into JSX produces this error's close cousin, "found: [object Date]". Convert it to text first —toLocaleDateString()for a friendly date,toISOString()for a precise one:<p>{new Date(post.created_at).toLocaleDateString()}</p> - Check what the API actually returned. If the render code looks right, suspect the data's shape. Real APIs wrap things: the array may live at
response.data, a single record may arrive inside an envelope, or an error object may have replaced the string you expected when a request failed. Put aconsole.logof the exact value one line above the render, reload, and look at the true shape before changing any JSX — guessing at shapes is how this fix turns into three new bugs. - For debugging only: JSON.stringify it. If you still cannot spot the object, temporarily render it as text:
The page un-crashes and shows you the object's real contents, keys and all — an X-ray of what you are holding. Then replace the stringify with the proper fields from steps 2 to 4. Do not ship the X-ray as the design; it is a diagnostic, not a layout.<pre>{JSON.stringify(item, null, 2)}</pre>
Why this happensOptional explanation
Everything inside curly braces in JSX is a promise: React, this value can be drawn on the page. Strings and numbers keep that promise — React turns them into text. Elements keep it too. A plain object breaks it: React has no way to know whether you wanted its title, its first field, or all of it, and instead of printing the useless text [object Object] like old-school JavaScript would, React stops and tells you exactly which object it choked on, keys included.
For vibe coders this error usually arrives at one predictable moment: the app graduates from hand-typed sample data to a real API or database. Sample data tends to be strings; real data is records — an object per post, per product, per user, often with objects nested inside other objects. Any place the JSX prints the record itself instead of a field of it becomes a crash the first time real data flows through.
- A whole record in braces:
{post}or{user}where{post.title}was intended. - A nested object: the field exists but is itself an object — an author, an address, a category — and needs one more step down.
- A Date or timestamp object: printed raw instead of being formatted into text first.
- An un-mapped list item or response wrapper: the array, or the object wrapping it, rendered directly instead of being mapped to elements.
Quick answers
It worked with my sample data. Why did connecting the real API break it?
Because the sample data was plain strings while the real API returns objects — often a wrapper object with the array inside, or records with nested objects for things like the author. The render code prints the value directly, so the shape change crashed it. Match the JSX to the real shape.
Why does console.log print the object fine but the page crashes?
The console is built to inspect objects; the page is built to paint them. React knows how to paint strings, numbers, and elements, and an object is none of those — there is no single right way to draw it, so React refuses loudly instead of guessing.
The error says object with keys {} — an empty object. What then?
Something rendered an object with no fields yet — classically a piece of state that starts as {} and fills in when data loads. Render a loading message or nothing until the field you display actually exists, e.g. show the title only once it has loaded.