{"record":{"id":"c09d60fc3a380290","repo":"mui/material-ui","slug":"duplicated-icons-in-legacy-folder-either-n1-rem","errorCode":null,"errorMessage":"Duplicated icons in legacy folder. Either \\n1. Remove these from the /legacy folder\\n2. Add them to the blacklist to keep the legacy version\\nThe following icons are duplicated: \\n${duplicatedIconsLegacy.join('\\n')}","messagePattern":"Duplicated icons in legacy folder\\. Either \\\\n1\\. Remove these from the /legacy folder\\\\n2\\. Add them to the blacklist to keep the legacy version\\\\nThe following icons are duplicated: \\\\n(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/mui-icons-material/builder.mjs","lineNumber":282,"sourceCode":"        svgPath,\n        options,\n        renameFilter,\n        template,\n      }),\n    { concurrency: 8 },\n  );\n\n  queue.push(svgPaths);\n  await queue.wait({ empty: true });\n\n  let legacyFiles = await globAsync(normalizePath(path.join(currentDirectory, '/legacy', '*.js')));\n  legacyFiles = legacyFiles.map((file) => path.basename(file));\n  let generatedFiles = await globAsync(normalizePath(path.join(options.outputDir, '*.js')));\n  generatedFiles = generatedFiles.map((file) => path.basename(file));\n\n  const duplicatedIconsLegacy = intersection(legacyFiles, generatedFiles);\n  if (duplicatedIconsLegacy.length > 0) {\n    throw new Error(\n      `Duplicated icons in legacy folder. Either \\n` +\n        `1. Remove these from the /legacy folder\\n` +\n        `2. Add them to the blacklist to keep the legacy version\\n` +\n        `The following icons are duplicated: \\n${duplicatedIconsLegacy.join('\\n')}`,\n    );\n  }\n\n  await fs.cp(path.join(currentDirectory, '/legacy'), options.outputDir, { recursive: true });\n  await fs.cp(path.join(currentDirectory, '/custom'), options.outputDir, { recursive: true });\n\n  await generateIndex(options);\n}\n\nconst nodePath = path.resolve(process.argv[1]);\nconst modulePath = path.resolve(fileURLToPath(import.meta.url));\nconst isRunningDirectlyViaCLI = nodePath === modulePath;\n\nif (isRunningDirectlyViaCLI) {","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/mui/material-ui/blob/bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5/packages/mui-icons-material/builder.mjs#L264-L300","documentation":"After generating icon files into outputDir, the builder globs the legacy/ folder and the generated files, computes their intersection by basename, and throws if any name appears in both. Legacy icons are meant to be one-of-a-kind overrides; a collision means a newly generated icon now shadows (or is shadowed by) a legacy one, so the build aborts and lists the duplicates.","triggerScenarios":"An icon added to the upstream Material Icons set whose name matches an existing file in packages/mui-icons-material/src/legacy; renaming a legacy file to collide with a generated name; running the build after pulling new upstream icons.","commonSituations":"Upstream Google added an icon whose name a legacy override already used; legacy folder left with stale files after a name normalisation change.","solutions":["If the generated version is now authoritative, delete the matching file(s) from the legacy/ folder.","If the legacy override must be kept, add the icon name to the blacklist so generation skips it (see the existing blacklist mechanism in builder.mjs/options).","Re-run the build to confirm the intersection is empty."],"exampleFix":"// before: legacy/Star.js exists and a generated Star.js is produced\n// option A — delete legacy override\nrimraf packages/mui-icons-material/src/legacy/Star.js\n// option B — blacklist it so only the legacy version ships (per the message)","handlingStrategy":"validation","validationCode":"import { globby } from 'globby';\nimport path from 'path';\nasync function findDuplicates(legacyDir, outputDir) {\n  const [legacy, generated] = await Promise.all([globby('*.js', { cwd: legacyDir }), globby('*.js', { cwd: outputDir })]);\n  return legacy.filter(f => generated.includes(f));\n}\n// bail before the build if duplicates is non-empty","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run a duplicate-name check in a pre-build script when upstream icons are refreshed.","Keep the legacy/ folder pruned of files that are now generated upstream.","Document the blacklist mechanism so contributors know how to keep a legacy override."],"tags":["build","icons","tooling","conflict","validation"],"backgroundTag":null,"analyzedSha":"bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5","analyzedAt":"2026-08-12T22:59:56.717Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}