mui/material-ui · error · Error
Expected a single child of the root
Error message
Expected a single child of the root
What it means
In the @mui/icons-material builder, an SVGO plugin (svgAsReactFragment) inspects the optimised SVG and asserts the document root has exactly one child. If the optimised SVG contains more than one top-level element (e.g. trailing whitespace nodes become elements, or two <svg> roots), the build throws. The generated icon component assumes a single <svg> root fragment child.
Source
Thrown at packages/mui-icons-material/builder.mjs:148
{ name: 'removeStyleElement' },
{ name: 'removeScripts' },
{ name: 'removeEmptyContainers' },
],
});
// True if the svg has multiple children
let childrenAsArray = false;
const jsxResult = svgo.optimize(result.data, {
plugins: [
{
name: 'svgAsReactFragment',
fn: () => {
return {
root: {
enter(root) {
const [svg, ...rootChildren] = root.children;
if (rootChildren.length > 0) {
throw new Error('Expected a single child of the root');
}
if (svg.type !== 'element' || svg.name !== 'svg') {
throw new Error('Expected an svg element as the root child');
}
if (svg.children.length > 1) {
childrenAsArray = true;
svg.children.forEach((svgChild, index) => {
svgChild.attributes.key = index;
// Original name will be restored later
// We just need a mechanism to convert the resulting
// svg string into an array of JSX elements
svgChild.name = `SVGChild:${svgChild.name}`;
});
}
root.children = svg.children;
},View on GitHub (pinned to bdc96df2cb)
Solutions
- Open the offending SVG in an editor and ensure it has a single <svg>...</svg> root with nothing outside it (no comments, text, or second root).
- Re-run the SVGO optimisation manually to inspect the post-optimisation output before feeding it to the builder.
- If the source is generated by download.mjs, re-download the icon and check the upstream gstatic SVG.
Example fix
<!-- before: two roots --> <svg>...</svg> <svg>...</svg> <!-- after --> <svg>...</svg>
Defensive patterns
Strategy: validation
Validate before calling
import { parse } from 'svg-parser';
function hasSingleRootChild(svgString) {
const ast = parse(svgString);
const root = ast.children.filter(c => c.type === 'root')[0];
return root.children.filter(c => c.type !== 'text' || c.value.trim().length > 0).length === 1;
}
// run before feeding the SVG to the builder Prevention
- Lint each icon source for a single <svg> root with no siblings before building.
- Run SVGO and inspect its output when adding new icons.
- Keep icon sources machine-generated (e.g. from a vector tool's SVG export).
When it happens
Trigger: Running the icon build/generator over an SVG source whose root has multiple element children after SVGO optimisation; corrupted/hand-edited SVG sources; an SVGO plugin config change that produces extra root nodes.
Common situations: Adding a new custom icon whose source SVG was concatenated from multiple fragments; SVGO version bump changing how comments/whitespace are preserved at the root.
Related errors
- Expected an svg element as the root child
- renameFilter must be a function
- Duplicated icons in legacy folder. Either \n1. Remove these
- docs-infra: The title "${title}" is too long (${title.length
- docs-infra: Missing description in the page: ${location}\n
AI-assisted analysis of mui/material-ui@bdc96df2cb (2026-08-12).
Data as JSON: /api/errors/b4b914e167c02aaa.
Report an issue: GitHub.