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

  1. 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.
  2. If the duplicate is intentional (platform-specific variants), confirm the platform extension is correct so they land on different platforms.
  3. If using a custom hasteImplModulePath, debug its getHasteName return value for the two paths.
  4. 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

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


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/58a6603753db9418.json. Report an issue: GitHub.