Diego Betto's Blog
Photo by Yoel Winkler on Unsplash

Diego Betto · September 10, 2026 · 4 min di lettura

"Objects are not valid as a React child": what it means and the three usual causes

Why JSX won't render an object directly, the three real-world cases that trigger it (Date, error objects, Map/Set), and how to fix each one.

Condividi:XLinkedInFacebookWhatsApp

You render something, expecting text, and instead get this crash:

⛔ Error

Objects are not valid as a React child (found: object with keys {year, month, day}). If you meant to render a collection of children, use an array instead.

The error is more helpful than most — it literally lists the keys of the object you tried to render, which is usually enough to spot the mistake immediately. Here are the three shapes it comes in most often.

Why this happens at all

JSX knows how to render strings, numbers, arrays of renderable things, and React elements. A plain JavaScript object isn’t any of those — React has no defined way to turn { year: 2026, month: 9 } into text, so instead of guessing (and silently showing [object Object], which is what String(obj) would produce), it throws.

const config = { year: 2026, month: 9, day: 10 };
return <p>{config}</p>; // throws — React doesn't know how to render this object

Cause #1: rendering a Date directly

function OrderDate({ order }) {
  // order.createdAt is a Date object, not a string
  return <p>{order.createdAt}</p>;
}

A Date is an object, not a string — you always need to format it first:

function OrderDate({ order }) {
  return <p>{order.createdAt.toLocaleDateString()}</p>;
}

If you’re formatting dates across the app already, this is also the exact use case for Temporal.PlainDate/ZonedDateTime, which forces you to call .toString() or a formatter explicitly rather than accidentally passing the raw object around.

Cause #2: rendering an entire error object instead of its message

Very common in a catch block or an error boundary’s fallback UI:

try {
  await submitForm(data);
} catch (error) {
  setError(error); // stores the whole Error object
}

// later, in the render:
return <p>{error}</p>; // throws — an Error instance is an object

The fix is to render the message, not the error object itself:

return <p>{error.message}</p>;

If you’re building a fallback UI for a caught render error rather than a caught async error, the same rule applies inside an error boundary’s componentDidCatch/getDerivedStateFromError.

Cause #3: rendering a Map or Set

const tags = new Map([
  ["js", "JavaScript"],
  ["ts", "TypeScript"],
]);
return <p>{tags}</p>; // throws

Neither Map nor Set are arrays, so JSX doesn’t know how to iterate them for you. Convert explicitly first:

return (
  <ul>
    {Array.from(tags.values()).map((tag) => (
      <li key={tag}>{tag}</li>
    ))}
  </ul>
);

Why arrays are fine, but objects aren’t

It’s worth noting the asymmetry, since it trips people up — an array of elements renders just fine:

<ul>{[<li key="1">A</li>, <li key="2">B</li>]}</ul> // works perfectly

React explicitly supports arrays of children. The distinction isn’t “objects vs. primitives,” it’s “does React have a defined rendering rule for this shape.” Arrays of renderable elements have one; plain data objects don’t.

FAQ

❓ Why doesn't React just call toString() on the object automatically?

It deliberately doesn’t, because that would usually produce [object Object] silently — a broken-looking UI with no error to tell you why. Throwing instead surfaces the mistake immediately, during development, rather than shipping a confusing bug to production.

❓ Does this apply to React Server Components too?

Yes — a Server Component still can’t render a raw object as a child, for the same reason. Where it gets slightly different is passing props between components: props sent from a Server Component to a Client Component must be serializable, which is a related but separate constraint from what can appear as rendered JSX content.

❓ Has React 19 changed this error message?

The underlying rule is unchanged, but React 19 improved the message’s clarity — earlier versions sometimes showed a less specific description of the object. The advice above applies to any recent React version.

Conclusion

“Objects are not valid as a React child” is JSX telling you it found a plain object where it expected text or renderable elements — almost always a Date, a full error object, or a Map/Set that needs converting first. The error message itself, listing the object’s keys, is usually enough to point you straight at the offending value.

References

Condividi:XLinkedInFacebookWhatsApp
Diego Betto

Written by

Diego Betto

Co-Founder & CTO at PAPION. Senior full-stack engineer specializing in React, TypeScript, Node.js, and application security.