HelloZeroNet/ZeroNet · error · Error
The selector for the root VNode may not be changed. (conside
Error message
The selector for the root VNode may not be changed. (consider using dom.merge and add one extra level to the virtual DOM)
What it means
createProjection's update function throws when the updated root vnode has a different vnodeSelector than the one the projection was created with. maquette only diffs against the same node type at the root; changing the root selector requires a different DOM structure, so it suggests dom.merge with an extra wrapper level.
Source
Thrown at plugins/UiConfig/media/js/lib/maquette.js:484
}
}
updated = updateChildren(vnode, domNode, previous.children, vnode.children, projectionOptions) || updated;
updated = updateProperties(domNode, previous.properties, vnode.properties, projectionOptions) || updated;
if (vnode.properties && vnode.properties.afterUpdate) {
vnode.properties.afterUpdate(domNode, projectionOptions, vnode.vnodeSelector, vnode.properties, vnode.children);
}
}
if (updated && vnode.properties && vnode.properties.updateAnimation) {
vnode.properties.updateAnimation(domNode, vnode.properties, previous.properties);
}
vnode.domNode = previous.domNode;
return textUpdated;
};
var createProjection = function (vnode, projectionOptions) {
return {
update: function (updatedVnode) {
if (vnode.vnodeSelector !== updatedVnode.vnodeSelector) {
throw new Error('The selector for the root VNode may not be changed. (consider using dom.merge and add one extra level to the virtual DOM)');
}
updateDom(vnode, updatedVnode, projectionOptions);
vnode = updatedVnode;
},
domNode: vnode.domNode
};
};
;
// The other two parameters are not added here, because the Typescript compiler creates surrogate code for desctructuring 'children'.
exports.h = function (selector) {
var properties = arguments[1];
if (typeof selector !== 'string') {
throw new Error();
}
var childIndex = 1;
if (properties && !properties.hasOwnProperty('vnodeSelector') && !Array.isArray(properties) && typeof properties === 'object') {
childIndex = 2;
} else {View on GitHub (pinned to 454c0b2e7e)
Solutions
- Keep the root vnode selector constant across updates.
- Wrap the variable content in a stable outer element, e.g. always return h('div', [conditionalContent]).
- Use dom.merge/dom.append with an extra wrapper level as the error message suggests.
- Tear down and re-create the projector/projection if the root must genuinely change.
Example fix
// before
projection.update(condition ? h('div', [x]) : h('span', [x]))
// after
projection.update(h('div', [condition ? x : y])) Defensive patterns
Strategy: validation
Validate before calling
function assertSameRootSelector(prevVnode, nextVnode) {
if (prevVnode.vnodeSelector !== nextVnode.vnodeSelector) {
throw new Error('Root selector must stay constant: ' + prevVnode.vnodeSelector);
}
}
Type guard
function sameRoot(prev, next) {
return prev.vnodeSelector === next.vnodeSelector;
} Try / catch
try {
projection.update(updatedVnode);
} catch (e) {
if (/selector for the root VNode may not be changed/.test(e.message)) {
projection = projector.createDom(wrapInStableRoot(updatedVnode), extensions);
} else { throw e; }
} Prevention
- Always return the same root element type from the top-level render function.
- Wrap variable content in a constant outer h('div', [...]) container.
- If the root must change, recreate the projection/projector instead of updating.
When it happens
Trigger: Calling projection.update(h('div', ...)) on a projection originally created from h('span', ...), or conditionally returning a different root element type from the top-level render function.
Common situations: Conditionally rendering different root tags (div vs span, or component vs null placeholder) from the root render function; refactoring a component's root element while a projector holds an old projection.
Related errors
- The selector for the root VNode may not be changed. (conside
- Provide a transitions object to the projectionOptions to do
- Style values must be strings
- Property "className" is not supported, use "class".
- "class" property may not be updated. Use the "classes" prope
AI-assisted analysis of HelloZeroNet/ZeroNet@454c0b2e7e (2026-09-02).
Data as JSON: /api/errors/f2c6c7947f571020.
Report an issue: GitHub.