{"record":{"id":"8b7b80e19762c4e8","repo":"preactjs/preact","slug":"expected-a-valid-html-node-as-a-second-argument-to","errorCode":null,"errorMessage":"Expected a valid HTML node as a second argument to render.\tReceived ${parentNode} instead: render(<${componentName} />, ${parentNode});","messagePattern":"Expected a valid HTML node as a second argument to render\\.\tReceived (.+?) instead: render\\(<(.+?) />, (.+?)\\);","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"debug/src/debug.js","lineNumber":134,"sourceCode":"\t\t\t\t'Undefined parent passed to render(), this is the second argument.\\n' +\n\t\t\t\t\t'Check if the element is available in the DOM/has the correct id.'\n\t\t\t);\n\t\t}\n\n\t\tlet isValid;\n\t\tswitch (parentNode.nodeType) {\n\t\t\tcase ELEMENT_NODE:\n\t\t\tcase DOCUMENT_FRAGMENT_NODE:\n\t\t\tcase DOCUMENT_NODE:\n\t\t\t\tisValid = true;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tisValid = false;\n\t\t}\n\n\t\tif (!isValid) {\n\t\t\tlet componentName = getDisplayName(vnode);\n\t\t\tthrow new Error(\n\t\t\t\t`Expected a valid HTML node as a second argument to render.\tReceived ${parentNode} instead: render(<${componentName} />, ${parentNode});`\n\t\t\t);\n\t\t}\n\n\t\tif (oldRoot) oldRoot(vnode, parentNode);\n\t};\n\n\toptions._diff = vnode => {\n\t\tlet { type } = vnode;\n\n\t\thooksAllowed = true;\n\n\t\tif (type === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'Undefined component passed to createElement()\\n\\n' +\n\t\t\t\t\t'You likely forgot to export your component or might have mixed up default and named imports' +\n\t\t\t\t\tserializeVNode(vnode) +\n\t\t\t\t\t`\\n\\n${getOwnerStack(vnode)}`","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/preactjs/preact/blob/e881e7e8386d7a430f87498a41c6a532992b4599/debug/src/debug.js#L116-L152","documentation":"Thrown from the options._root hook when the parentNode is truthy but its nodeType is not one of ELEMENT_NODE (1), DOCUMENT_FRAGMENT_NODE (11), or DOCUMENT_NODE (9). Preact can only mount into a real DOM node, a fragment, or the document itself; anything else (text node, comment, attribute node, a plain JS object) is rejected with a message echoing the component name and the bad value.","triggerScenarios":"Passing a text node (document.createTextNode('x')), a comment node, or an attribute node as the render target; passing a jQuery-wrapped collection or a plain object that lacks nodeType; passing the result of querySelector that unexpectedly returned a non-element; passing document.doctype or a processing instruction.","commonSituations":"Mixing jQuery and Preact and handing over a $() collection instead of $()[0]; test utilities that pass a detached string-HTML fragment object; SSR-to-client handoff where the target is a serialized node rather than a live element; code written for React that passes a document fragment created offscreen.","solutions":["Ensure the second argument is a single Element: use document.querySelector('#app') (returns Element|null) rather than a NodeList or wrapper.","If using jQuery, unwrap with [0]: render(<App/>, $('#app').get(0)).","For shadow DOM or fragments, pass the actual ShadowRoot (nodeType 11) or a DocumentFragment created via document.createDocumentFragment().","Log parentNode.nodeType before render — it must be 1, 9, or 11."],"exampleFix":"// before\nimport $ from 'jquery';\nrender(<App />, $('#app'));\n\n// after\nimport $ from 'jquery';\nrender(<App />, $('#app').get(0));","handlingStrategy":"validation","validationCode":"function resolveMountNode(selectorOrEl) {\n  const el = typeof selectorOrEl === 'string'\n    ? document.querySelector(selectorOrEl)\n    : selectorOrEl;\n  if (!el || ![1, 9, 11].includes(el.nodeType)) {\n    throw new Error(`Invalid mount target: ${el}`);\n  }\n  return el;\n}\n\nrender(<App />, resolveMountNode('#app'));","typeGuard":"/** @param {unknown} n */\nfunction isPreactMountTarget(n) {\n  if (n == null || typeof n !== 'object') return false;\n  const t = /** @type {Node} */ (n).nodeType;\n  return t === 1 || t === 9 || t === 11;\n}","tryCatchPattern":null,"preventionTips":["Always unwrap jQuery collections with .get(0) or [0].","Prefer querySelector over getElementById when unsure — both return Element|null.","When using Shadow DOM, pass the ShadowRoot (nodeType 11) directly."],"tags":["preact","render","dom","node-type","debug-build"],"backgroundTag":null,"analyzedSha":"e881e7e8386d7a430f87498a41c6a532992b4599","analyzedAt":"2026-08-13T04:27:04.532Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}