The Error
Your component throws this in the browser console:
Objects are not valid as a React child. If you meant to render a collection of children, use an array instead.
The app crashes or goes blank. The stack trace points somewhere inside your JSX โ but the real culprit is usually a few lines above that.
Root Cause
React knows how to render strings, numbers, booleans, arrays, and React elements. Plain JavaScript objects and Promises? It has no idea what to do with them. Pass one of those as a JSX child and React bails out with this error.
The usual suspects:
- Rendering a whole object
{user}instead of a field like{user.name} - Rendering a
Dateobject โnew Date()is not a string, no matter how much it looks like one - Rendering a Promise โ you forgot to
awaitthat async call - Dumping a raw API response into JSX before drilling into the actual value
- Calling
Object.keys()orObject.entries()and forgetting to.map()over the result
How to Find the Exact Cause
Check the full error message in the browser console. React is surprisingly helpful here:
Error: Objects are not valid as a React child (found: object with keys {id, name, email}).
Those keys are your clue. Search your component for anywhere that shape of object flows into JSX.
Still not obvious? Drop a quick log just before your return:
console.log(typeof someVariable, someVariable);
If typeof says "object" and that variable ends up as a child โ you found it.
Fix 1 โ Access the Property, Not the Object
Nine times out of ten, this is the problem. You passed the entire object when you only needed one field.
// โ Wrong โ renders the entire user object
function UserCard({ user }) {
return {user}
;
}
// โ
Fixed โ render a specific property
function UserCard({ user }) {
return {user.name}
;
}
Fix 2 โ Convert Date Objects to Strings
Date objects are not renderable. Pick a string method: .toLocaleDateString(), .toISOString(), or .toLocaleString() depending on how you want it formatted.
// โ Wrong
const createdAt = new Date(post.createdAt);
return {createdAt};
// โ
Fixed
return {createdAt.toLocaleDateString()};
Fix 3 โ Await the Promise Before Rendering
Async functions return Promises. Call one without await and you get a Promise object back โ not the data inside it.
// โ Wrong โ fetchUser returns a Promise, not a user
function Profile() {
const user = fetchUser();
return {user.name}
;
}
// โ
Fixed โ useEffect + useState handles the async lifecycle
function Profile() {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then(setUser);
}, []);
if (!user) return Loading...
;
return {user.name}
;
}
Fix 4 โ Stringify JSON for Debugging
Want to eyeball raw API data during development? Use JSON.stringify(). Passing the object directly won't work.
// โ Wrong โ renders the whole object
return ```
{data}
```;
// โ
Fixed โ readable, indented JSON string
return ```
{JSON.stringify(data, null, 2)}
```;
Strip this out before shipping to production โ it's a debug tool, not UI.
Fix 5 โ Map Over Collections Correctly
Object.entries() returns an array of [key, value] pairs. That array is not automatically renderable โ you still need to .map() it into JSX elements.
// โ Wrong โ Object.entries returns an array of arrays, not JSX
const settings = { theme: 'dark', lang: 'en' };
return {Object.entries(settings)};
// โ
Fixed โ each entry becomes a list item
return (
{Object.entries(settings).map(([key, value]) => (
- {key}: {value}
))}
);
Fix 6 โ Guard Against Unknown Value Types
Sometimes you don't control what shape a value arrives in โ especially with third-party APIs. Add a type check before rendering.
// โ Wrong โ crashes if response is an object, not a string
return {response}
;
// โ
Safe โ only renders if it's actually a string or number
return {typeof response === 'string' ? response : null}
;
Verification
After the fix, three things should be true:
- The error overlay in the browser is gone
- The component renders without crashing
- Your test suite passes:
npm testorpnpm test
If the error persists, the object is probably coming from a different part of the component tree. Follow the keys listed in the error message โ they'll lead you there.
Prevention Tips
TypeScript catches this at compile time. Type a prop as string and TypeScript won't let you accidentally pass a User object in its place. This eliminates the entire class of bug before the browser ever sees it.
interface Props {
name: string; // callers must pass a string, not an object
}
function Label({ name }: Props) {
return {name};
}
Destructure API responses at the boundary. Pull out the fields you actually need right where the data enters your app โ before it spreads into components. For deeply nested or unfamiliar JSON, paste the response into JSON Formatter & Validator to visualize the structure and confirm which keys to target. Everything runs in the browser; nothing gets uploaded.
No TypeScript? Use PropTypes for lightweight runtime validation:
import PropTypes from 'prop-types';
UserCard.propTypes = {
user: PropTypes.shape({
name: PropTypes.string.isRequired,
}).isRequired,
};

