{"record":{"id":"556ac062875dfc05","repo":"mui/material-ui","slug":"renamefilter-must-be-a-function","errorCode":null,"errorMessage":"renameFilter must be a function","messagePattern":"renameFilter must be a function","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/mui-icons-material/builder.mjs","lineNumber":249,"sourceCode":"    componentName,\n  });\n\n  const absDestPath = path.join(options.outputDir, destPath);\n  await fs.writeFile(absDestPath, fileString);\n}\n\nexport async function handler(options) {\n  const progress = options.disableLog ? () => {} : () => process.stdout.write('.');\n\n  rimrafSync(`${options.outputDir}/*.js`, { glob: true }); // Clean old files\n\n  let renameFilter = options.renameFilter;\n  if (typeof renameFilter === 'string') {\n    const renameFilterModule = await import(renameFilter);\n    renameFilter = renameFilterModule.default;\n  }\n  if (typeof renameFilter !== 'function') {\n    throw new Error('renameFilter must be a function');\n  }\n  await fs.mkdir(options.outputDir, { recursive: true });\n\n  const [svgPaths, template] = await Promise.all([\n    globAsync(normalizePath(path.join(options.svgDir, options.glob))),\n    fs.readFile(path.join(currentDirectory, 'templateSvgIcon.js'), {\n      encoding: 'utf8',\n    }),\n  ]);\n\n  const queue = new Queue(\n    (svgPath) =>\n      worker({\n        progress,\n        svgPath,\n        options,\n        renameFilter,\n        template,","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/mui/material-ui/blob/bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5/packages/mui-icons-material/builder.mjs#L231-L267","documentation":"The icons builder accepts a `renameFilter` option that is either a function or a string path to a module whose default export is the function (it dynamically imports the string). After that resolution, if renameFilter is still not a function, it throws. The filter maps each SVG path to a destination filename/component name, so a non-function would silently break generation.","triggerScenarios":"Passing options.renameFilter that is neither a function nor a resolvable module path; passing a module path whose default export is undefined or not a function; passing a plain object by mistake.","commonSituations":"Customising icon output paths/names with a user-supplied filter; the filter module was refactored to a named export instead of default; a CLI flag passed an object string that failed JSON.parse elsewhere.","solutions":["Pass renameFilter as a function: (opts) => computedName.","If using a module path, ensure the module has `export default function ...` (default export).","Verify the module path resolves and the default export is callable."],"exampleFix":"// before — module has only a named export\n// myFilter.js: export function myFilter(opts) { ... }\n// caller: renameFilter: './myFilter.js'\n// after\n// myFilter.js: export default function myFilter(opts) { ... }\n// caller: renameFilter: './myFilter.js'","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isRenameFilter(value) {\n  return typeof value === 'function';\n}\n// after resolving a string module path:\nif (!isRenameFilter(renameFilter)) throw new Error('renameFilter resolved to a non-function');","tryCatchPattern":null,"preventionTips":["Always default-export your custom filter module.","Pass renameFilter as an inline function when possible to avoid module resolution ambiguity.","Unit-test the filter module's default export before wiring it into the build."],"tags":["build","icons","tooling","configuration","validation"],"backgroundTag":null,"analyzedSha":"bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5","analyzedAt":"2026-08-12T22:59:56.717Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}