Your AI coding agent put an object in JSX, and React throws Objects are not valid as a React child

AI coding agents render a whole user record, a Date or an error straight into JSX. React cannot draw an object and throws. Here is how to read the found: part, and the field-level fix.

انتقل إلى الإصلاح
في هذه الصفحة

Your agent added a line that shows a date, an API response, or a user record inside JSX. The page goes blank and the console says Objects are not valid as a React child (found: ...). The data is there and the component looks fine. React is refusing to turn one specific value into something it can draw.

Why this happens

The error text is fixed in React’s own error decoder: “Objects are not valid as a React child (found: %s). If you meant to render a collection of children, use an array instead.” The %s is filled in with what React found, which is the useful part of the message.

JSX can display strings and numbers, other elements, and arrays of those. It cannot display a plain object, because there is no single way to turn { id: 4, name: "Sam" } into text. When you write {user} instead of {user.name}, React gets the whole object and throws.

AI agents trigger this in a few predictable ways:

  • Rendering a whole record such as {user} or {order} instead of one field.
  • Rendering a Date such as {post.createdAt} after the data has been parsed. A Date is an object, not text.
  • Rendering a response or error such as {error} in a catch block. An Error object is not a string.
  • Rendering a Promise, which happens when an async call is placed straight in JSX without awaiting it.

How to tell if this is your problem

  1. Read the found: part of the message. It names the shape. object with keys {id, name, email} is a record. [object Promise] is an unawaited call. [object Date] is a date.
  2. Open the component in the stack trace and look for curly braces that hold a bare variable name rather than a property or a call.
  3. Log the value right above the return: console.log(typeof value, value). If typeof says object, that is the line.

The fix

Render a field, or convert the value to text on purpose:

// Before: the whole object
<p>{user}</p>

// After: the field you meant
<p>{user.name}</p>

// A date, converted explicitly
<p>{new Date(post.createdAt).toLocaleDateString()}</p>

// An error, as its message
<p>{error instanceof Error ? error.message : String(error)}</p>

If you do want a list, the error message tells you how: use an array, and give each item a key.

<ul>
  {users.map((u) => (
    <li key={u.id}>{u.name}</li>
  ))}
</ul>

When the value is a promise, resolve it before rendering. In a client component, load it in an effect or a data library and render the result once it exists, with a loading state for the gap.

If you only need to see the data

For debugging, <pre>{JSON.stringify(value, null, 2)}</pre> prints any plain object safely. Remove it before you ship, since it can expose fields you did not mean to show.

How to avoid this next time

Add a rule to your agent’s instructions: “Never place an object, Date, Error or Promise directly in JSX. Render a specific field, format dates and errors to strings, and map arrays with a stable key.” In review, scan the curly braces in the returned markup: every one should hold text, a number, an element, or an array of those.

Comments