facebook/react · error · Error
31
31
Error message
Objects are not valid as a React child (found: ${childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString}). If you meant to render a collection of children, use an array instead. What it means
Fizz's renderNodeDestructive accepts strings, numbers, arrays, iterables, React elements, thenables, and contexts as children. A plain object reaches the final branch and throws error code 31; the message reports Object.prototype.toString of the value and, for plain objects, lists its keys.
Source
Thrown at packages/react-server/src/ReactFizzServer.js:3726
childIndex,
);
return result;
}
if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE) {
const context: ReactContext<ReactNodeList> = maybeUsable as any;
return renderNodeDestructive(
request,
task,
readContext(context),
childIndex,
);
}
// $FlowFixMe[method-unbinding]
const childString = Object.prototype.toString.call(node);
throw new Error(
`Objects are not valid as a React child (found: ${
childString === '[object Object]'
? 'object with keys {' + Object.keys(node).join(', ') + '}'
: childString
}). ` +
'If you meant to render a collection of children, use an array ' +
'instead.',
);
}
if (typeof node === 'string') {
const segment = task.blockedSegment;
if (segment === null) {
// We assume a text node doesn't have a representation in the replay set,
// since it can't postpone. If it does, it'll be left unmatched and error.
} else {
segment.lastPushedText = pushTextInstance(
segment.chunks,View on GitHub (pinned to eafeac097b)
Solutions
- Convert objects to primitives before rendering: toISOString(), String(...), Array.from(...), or JSON.stringify(...)
- Render collections as arrays: Object.entries(obj).map(([k, v]) => ...)
- Pass objects as props to child components instead of rendering them as children
Example fix
// before
<div>{new Date(post.createdAt)}</div> // renders '[object Date]' branch -> throws
// after
<div>{new Date(post.createdAt).toISOString()}</div> Defensive patterns
Strategy: validation
Validate before calling
function assertRenderableChildren(node) {
if (node == null || typeof node === 'string' || typeof node === 'number' || typeof node === 'boolean') return;
if (Array.isArray(node)) return node.forEach(assertRenderableChildren);
if (typeof node === 'object' && node.$$typeof != null) return; // React element
throw new TypeError('Objects are not valid as a React child: ' + Object.prototype.toString.call(node));
} Type guard
function isRenderableChild(node) {
return (
node == null ||
typeof node === 'string' ||
typeof node === 'number' ||
typeof node === 'boolean' ||
Array.isArray(node) ||
(typeof node === 'object' && node.$$typeof != null)
);
} Prevention
- Convert dates, Maps, Sets, and plain objects to primitives before putting them in JSX
- Type children props as ReactNode so TypeScript rejects object children
- Smoke-render server components in dev to catch stray objects early
When it happens
Trigger: Rendering {config}, new Date(), a Map or Set, an Error instance, an ORM row, or any class instance directly as a JSX child during SSR.
Common situations: Passing server data straight into JSX (API objects, i18n bundles, URLSearchParams); forgetting toISOString()/toString()/join(); children props that unexpectedly contain an object.
Related errors
- <textarea> can only have at most one child.
- Objects are not valid as a React child (found: ${childrenStr
- 62
- File/Blob fields are not yet supported in progressive forms.
- Can only set one of `children` or `props.dangerouslySetInner
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/b303b7e56af4fddf.
Report an issue: GitHub.