angular/angular-cli · error · Error
Multiple bundles have been named the same: '${duplicates.joi
Error message
Multiple bundles have been named the same: '${duplicates.join(`', '`)}'. What it means
generateEntryPoints assembles the initial webpack entry-point list (runtime, polyfills, styles, scripts, vendor, main) from injectable styles/scripts in the build options. If any bundle name collides, the duplicates check fires this error so the produced HTML does not contain ambiguous, overwriting script tags. In the checked-in code the duplicate scan only compares against the first entry (runtime) via entryPoints[0], so it only reliably catches a name colliding with 'runtime', though the intent is to reject any duplicate bundle name.
Source
Thrown at packages/angular_devkit/build_angular/src/utils/package-chunk-sort.ts:46
// remove duplicates
return [...new Set(entryPoints)].map<EntryPointsType>((f) => [f, false]);
};
const entryPoints: EntryPointsType[] = [
['runtime', !options.isHMREnabled],
['polyfills', true],
...extraEntryPoints(options.styles, 'styles'),
...extraEntryPoints(options.scripts, 'scripts'),
['vendor', true],
['main', true],
];
const duplicates = entryPoints.filter(
([name]) => entryPoints[0].indexOf(name) !== entryPoints[0].lastIndexOf(name),
);
if (duplicates.length > 0) {
throw new Error(`Multiple bundles have been named the same: '${duplicates.join(`', '`)}'.`);
}
return entryPoints;
}
View on GitHub (pinned to bb72145f9a)
Solutions
- Set an explicit unique "bundleName" on the conflicting scripts/styles entry in angular.json.
- Rename the source file so its basename does not collide with reserved bundle names (main, runtime, polyfills, styles, scripts, vendor).
- If two extra entries collide with each other, merge them or give each a distinct bundleName.
- Verify inject: false for entries that should not participate in the initial entry list.
Example fix
// before (angular.json)
"scripts": [{ "input": "node_modules/some-lib/main.js", "inject": true }]
// after
"scripts": [{ "input": "node_modules/some-lib/main.js", "inject": true, "bundleName": "some-lib" }] Defensive patterns
Strategy: validation
Validate before calling
// Detect colliding bundle names before building
const RESERVED = ['runtime', 'polyfills', 'styles', 'scripts', 'vendor', 'main'];
function findBundleNameCollisions(scripts = [], styles = []) {
const names = [];
for (const e of [...scripts, ...styles]) {
if (e.inject === false) continue;
const name = e.bundleName ??
require('path').basename(e.input.split('*').pop().replace(/\.[jt]sx?$/, '').replace(/\.(css|scss|sass|less|styl)$/, ''), '.js');
names.push(name);
}
return [...new Set(names.filter(n => RESERVED.includes(n) || names.indexOf(n) !== names.lastIndexOf(n)))];
} Try / catch
try {
const entryPoints = generateEntryPoints(options);
return entryPoints;
} catch (err) {
if (/^Multiple bundles have been named the same:/.test(err?.message ?? '')) {
console.error('Assign a unique "bundleName" to the conflicting styles/scripts entry in angular.json.');
} else throw err;
} Prevention
- Give every injected scripts/styles entry an explicit unique "bundleName" in angular.json.
- Avoid naming extra entry source files main.*, styles.*, scripts.*, vendor.*, runtime.* or polyfills.*.
- Diff bundle names after Angular CLI upgrades, since default bundle naming for extra entries has changed across versions.
When it happens
Trigger: Building with angular.json styles or scripts entries whose computed bundleName (glob basename, or explicit bundleName via normalizeExtraEntryPoints) collides with a reserved entry name — 'runtime', 'polyfills', 'styles', 'scripts', 'vendor', 'main', or another extra entry — and inject: true.
Common situations: Adding a script like node_modules/x/main.js (bundleName 'main') or a style named 'styles.css' from a nonstandard path, after upgrades where default bundle naming changed (e.g. extra entries now default to 'scripts'/'styles'), or two extra entries resolving to the same bundleName.
Related errors
- No options were specified to "postcss-cli-resources".
- Unsupported package manager: "${name}"
- The configured package manager, '${this.descriptor.binary}',
- Project "${project}" does not exist.
- Project target does not exist.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/bb5af9924fdc6cdd.
Report an issue: GitHub.