{"record":{"id":"7948a7fb9216a614","repo":"preactjs/preact","slug":"objects-are-not-valid-as-a-child-encountered-an-o","errorCode":null,"errorMessage":"Objects are not valid as a child. Encountered an object with the keys {${keys}}.\n\n${getOwnerStack(vnode)}","messagePattern":"Objects are not valid as a child\\. Encountered an object with the keys (.+?)\\.\n\n(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"debug/src/debug.js","lineNumber":339,"sourceCode":"\t\t// eslint-disable-next-line\n\t\tvnode.__proto__ = deprecatedProto;\n\t\tif (oldVnode) oldVnode(vnode);\n\t};\n\n\toptions.diffed = vnode => {\n\t\tconst { type, _parent: parent } = vnode;\n\t\t// Check if the user passed plain objects as children. Note that we cannot\n\t\t// move this check into `options.vnode` because components can receive\n\t\t// children in any shape they want (e.g.\n\t\t// `<MyJSONFormatter>{{ foo: 123, bar: \"abc\" }}</MyJSONFormatter>`).\n\t\t// Putting this check in `options.diffed` ensures that\n\t\t// `vnode._children` is set and that we only validate the children\n\t\t// that were actually rendered.\n\t\tif (vnode._children) {\n\t\t\tvnode._children.forEach(child => {\n\t\t\t\tif (typeof child === 'object' && child && child.type === undefined) {\n\t\t\t\t\tconst keys = Object.keys(child).join(',');\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Objects are not valid as a child. Encountered an object with the keys {${keys}}.` +\n\t\t\t\t\t\t\t`\\n\\n${getOwnerStack(vnode)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tif (vnode._component === currentComponent) {\n\t\t\trenderCount = 0;\n\t\t}\n\n\t\tif (\n\t\t\ttypeof type === 'string' &&\n\t\t\t(isTableElement(type) ||\n\t\t\t\ttype === 'p' ||\n\t\t\t\ttype === 'a' ||\n\t\t\t\ttype === 'button')\n\t\t) {","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/preactjs/preact/blob/e881e7e8386d7a430f87498a41c6a532992b4599/debug/src/debug.js#L321-L357","documentation":"Thrown from options.diffed after a vnode's children are resolved: if any rendered child is a plain object (typeof 'object', truthy) with no `type` property, Preact rejects it. Valid children are primitives (string/number), arrays, booleans/null/undefined (ignored), or vnodes (which carry a `type`). A bare object literal like `{foo:1}` as a child is not renderable. The check runs in diffed (not vnode) so component children that intentionally accept object shapes are not falsely flagged — only actually-rendered plain objects are caught.","triggerScenarios":"Passing an object literal as a child: `<div>{ {foo:1} }</div>`; interpolating a state object directly: `<span>{user}</span>` where user is an object; returning an object from a map callback into children: `items.map(i => ({id: i.id}))`; spreading a props object into children by mistake.","commonSituations":"Forgetting to access a property: `<div>{user}</div>` instead of `<div>{user.name}</div>`; passing a Map/Set/Error object as a child expecting implicit toString; mock data shaped as objects fed directly into JSX; converting an API response object to children without serialization.","solutions":["Render a specific property: `<div>{user.name}</div>` rather than the whole object.","Serialize explicitly: `<pre>{JSON.stringify(obj, null, 2)}</pre>` for debugging.","For lists, map to elements: `items.map(i => <li key={i.id}>{i.label}</li>)`.","If the object is a vnode-like wrapper, ensure it has a `type` — otherwise wrap it in a component."],"exampleFix":"// before\nfunction Greeting({ user }) {\n  return <div>Hello {user}</div>; // user is an object\n}\n\n// after\nfunction Greeting({ user }) {\n  return <div>Hello {user.name}</div>;\n}","handlingStrategy":"type-guard","validationCode":"function sanitizeChildren(children) {\n  const arr = Array.isArray(children) ? children : [children];\n  return arr.map(c => {\n    if (c != null && typeof c === 'object' && !('type' in c) &&\n        !Array.isArray(c) && !(c instanceof Date) && typeof c !== 'boolean') {\n      return JSON.stringify(c);\n    }\n    return c;\n  });\n}\n\n// before render\nreturn <div>{sanitizeChildren(maybeObjectChild)}</div>;","typeGuard":"/** @param {unknown} c */\nfunction isRenderableChild(c) {\n  if (c == null || typeof c === 'boolean') return true; // ignored\n  if (typeof c === 'string' || typeof c === 'number') return true;\n  if (Array.isArray(c)) return c.every(isRenderableChild);\n  if (typeof c === 'object') return 'type' in c; // vnode\n  return false;\n}","tryCatchPattern":null,"preventionTips":["Always access a specific property when interpolating an object: `{user.name}` not `{user}`.","Serialize objects explicitly with JSON.stringify when debugging.","Map data arrays to elements with keys; never render a raw object array.","Type children strictly in TS: `ReactNode`/`ComponentChild` to surface object children at compile time."],"tags":["preact","children","object-child","jsx","debug-build"],"backgroundTag":null,"analyzedSha":"e881e7e8386d7a430f87498a41c6a532992b4599","analyzedAt":"2026-08-13T04:27:04.532Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}