preactjs/preact · critical · Error
Expected a valid HTML node as a second argument to render. R
Error message
Expected a valid HTML node as a second argument to render. Received ${parentNode} instead: render(<${componentName} />, ${parentNode}); What it means
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.
Source
Thrown at debug/src/debug.js:134
'Undefined parent passed to render(), this is the second argument.\n' +
'Check if the element is available in the DOM/has the correct id.'
);
}
let isValid;
switch (parentNode.nodeType) {
case ELEMENT_NODE:
case DOCUMENT_FRAGMENT_NODE:
case DOCUMENT_NODE:
isValid = true;
break;
default:
isValid = false;
}
if (!isValid) {
let componentName = getDisplayName(vnode);
throw new Error(
`Expected a valid HTML node as a second argument to render. Received ${parentNode} instead: render(<${componentName} />, ${parentNode});`
);
}
if (oldRoot) oldRoot(vnode, parentNode);
};
options._diff = vnode => {
let { type } = vnode;
hooksAllowed = true;
if (type === undefined) {
throw new Error(
'Undefined component passed to createElement()\n\n' +
'You likely forgot to export your component or might have mixed up default and named imports' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`View on GitHub (pinned to e881e7e838)
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.
Example fix
// before
import $ from 'jquery';
render(<App />, $('#app'));
// after
import $ from 'jquery';
render(<App />, $('#app').get(0)); Defensive patterns
Strategy: validation
Validate before calling
function resolveMountNode(selectorOrEl) {
const el = typeof selectorOrEl === 'string'
? document.querySelector(selectorOrEl)
: selectorOrEl;
if (!el || ![1, 9, 11].includes(el.nodeType)) {
throw new Error(`Invalid mount target: ${el}`);
}
return el;
}
render(<App />, resolveMountNode('#app')); Type guard
/** @param {unknown} n */
function isPreactMountTarget(n) {
if (n == null || typeof n !== 'object') return false;
const t = /** @type {Node} */ (n).nodeType;
return t === 1 || t === 9 || t === 11;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Undefined parent passed to render(), this is the second argu
- Undefined component passed to createElement() You likely fo
- Invalid type passed to createElement(): ${type} Did you acc
- Invalid type passed to createElement(): ${Array.isArray(type
- Component's "ref" property should be a function, or an objec
AI-assisted analysis of preactjs/preact@e881e7e838 (2026-08-13).
Data as JSON: /api/errors/8b7b80e19762c4e8.
Report an issue: GitHub.