jestjs/jest · error · DuplicateError
Duplicated files or mocks. Please check the console for more
Error message
Duplicated files or mocks. Please check the console for more info
What it means
While processing each file, FileProcessor.assigns haste module IDs. When two different file paths resolve to the same haste ID on the same platform (a naming collision), and the `throwOnModuleCollision` option is true, it throws a DuplicateError whose message is generic but whose mockPath1/mockPath2 carry the colliding paths. The console also receives a detailed 'Haste module naming collision' message immediately before the throw.
Source
Thrown at packages/jest-haste-map/src/lib/FileProcessor.ts:106
H.GENERIC_PLATFORM;
const existingModule = moduleMap[platform];
if (existingModule && existingModule[H.PATH] !== module[H.PATH]) {
const method = this._options.throwOnModuleCollision ? 'error' : 'warn';
this._console[method](
[
`jest-haste-map: Haste module naming collision: ${id}`,
' The following files share their name; please adjust your hasteImpl:',
` * <rootDir>${path.sep}${existingModule[H.PATH]}`,
` * <rootDir>${path.sep}${module[H.PATH]}`,
'',
].join('\n'),
);
if (this._options.throwOnModuleCollision) {
throw new DuplicateError(existingModule[H.PATH], module[H.PATH]);
}
// We do NOT want consumers to use a module that is ambiguous.
delete moduleMap[platform];
if (Object.keys(moduleMap).length === 0) {
map.delete(id);
}
let dupsByPlatform = hasteMap.duplicates.get(id);
if (dupsByPlatform == null) {
dupsByPlatform = new Map();
hasteMap.duplicates.set(id, dupsByPlatform);
}
const dups = new Map([
[module[H.PATH], module[H.TYPE]],
[existingModule[H.PATH], existingModule[H.TYPE]],View on GitHub (pinned to f49721c78e)
Solutions
- Read the console output immediately preceding the throw — it lists both colliding paths and the shared id; rename one file or update its haste header.
- If the duplicate is intentional (platform-specific variants), confirm the platform extension is correct so they land on different platforms.
- If using a custom hasteImplModulePath, debug its getHasteName return value for the two paths.
- If collisions are acceptable in your workflow, set throwOnModuleCollision:false (Jest then warns and drops the ambiguous entry).
Example fix
// before — two files both declare `@providesModule Button` // src/Button.js -> Button // src/legacy/Button.js -> Button (collision) // after — rename one haste module // src/legacy/Button.js -> `@providesModule LegacyButton`
Defensive patterns
Strategy: validation
Validate before calling
// Before enabling throwOnModuleCollision, scan for duplicate haste IDs.
// Example: gather @providesModule names and report duplicates without throwing.
import {readFileSync} from 'node:fs';
const names = new Map(); // name -> [files]
for (const f of fileList) {
const m = /@providesModule\s+(\S+)/.exec(readFileSync(f, 'utf8'));
if (m) names.set(m[1], [...(names.get(m[1]) ?? []), f]);
}
const dupes = [...names.entries()].filter(([, files]) => files.length > 1);
if (dupes.length) console.warn('haste collisions:', dupes); Try / catch
import {DuplicateError} from 'jest-haste-map';
try {
await hasteMap.build();
} catch (err) {
if (err instanceof DuplicateError) {
console.error('collision between', err.mockPath1, 'and', err.mockPath2);
}
throw err;
} Prevention
- Run a duplicate-haste-ID scan in CI before enabling throwOnModuleCollision.
- Keep throwOnModuleCollision:false locally (warn) and true only in CI to fail on collisions without blocking dev.
- Use platform extensions correctly so platform variants do not collide on the generic platform.
When it happens
Trigger: processFile() → setModule() finds existingModule[H.PATH] !== module[H.PATH] for the same id+platform (FileProcessor.ts:92); throwOnModuleCollision is true (line 105 → 106). The duplicate typically comes from two files that a hasteImpl (or platform extension resolution) maps to the same module name.
Common situations: Two files with the same @providesModule / haste name; an RN-style module duplicated across vendor forks; enabling throwOnModuleCollision in CI to enforce uniqueness; a buggy custom hasteImplModulePath returning colliding names; copying a file without renaming its haste header.
Related errors
- jest-haste-map: the `ignorePattern` option must be a RegExp
- jest-haste-map: enableSymlinks config option was set, but is
- The --config option requires a JSON string literal, or a fil
- Cannot merge config in form of callback
- Whoops! Two projects resolved to the same config path: ${Str
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/58a6603753db9418.json.
Report an issue: GitHub.