Skip to content
Latchkey

Jest "jest-haste-map: duplicate manual mock found" / Naming Collision

Jest’s Haste module map requires each module name to be unique. The error means two files claim the same name - usually a duplicated package.json "name" in a build/output folder, or two __mocks__ files for the same module.

What this error means

Jest prints "jest-haste-map: Haste module naming collision" (or "duplicate manual mock found") listing two file paths that share a name. One of the paths is frequently a dist/build copy that should never have been scanned.

Jest output
jest-haste-map: Haste module naming collision: my-pkg

  The following files share their name; please adjust your hasteImpl:
    * <rootDir>/package.json
    * <rootDir>/dist/package.json

Diagnose it: flake, environment, or genuine failure?

Before debugging the assertion, establish whether the test is deterministic. A test that fails only in CI is usually order-dependent, time-dependent, or racing something, and fixing the assertion will not help.

Terminal
# does it fail in isolation?
npx vitest run path/to/file.test.ts

# is it order dependent? run the suite in a random order twice
npx vitest run --sequence.shuffle

# is it a race? run the same file repeatedly
for i in $(seq 1 20); do npx vitest run path/to/file.test.ts || break; done

Common causes

A build output copy is scanned alongside the source

A dist/build/coverage folder contains a copied package.json (or duplicated modules). Jest’s Haste map sees the same name twice and reports a collision.

Two manual mocks for the same module

Two __mocks__/<name>.js files (in different folders) target the same module name, so Jest cannot decide which manual mock to use.

How to fix it

Ignore build output in modulePathIgnorePatterns

Exclude generated folders so their copied files never enter the Haste map.

jest.config.js
// jest.config.js
module.exports = {
  modulePathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/build/'],
};

Resolve duplicate manual mocks

  1. Keep a single __mocks__/<name>.js per module name.
  2. Clean stale build output before running Jest (rm -rf dist in CI).
  3. Re-run once with --no-cache so a stale Haste map is rebuilt.

CI-only causes worth ruling out

  • Runners have fewer cores than a laptop, so timing-sensitive tests that pass locally fail under contention.
  • No TTY and a different locale or timezone. Snapshot tests containing formatted dates or numbers are the usual casualty; pin TZ and LANG in the job.
  • Parallel workers sharing a database, a port, or a temp directory. Give each worker its own namespace.
  • Default timeouts calibrated on a fast machine. A cold runner is slower on first execution, especially before any cache warms.

How to prevent it

  • Add dist/build/coverage to modulePathIgnorePatterns.
  • Clean generated output before test runs in CI.
  • Keep exactly one manual mock per module name.

Frequently asked questions

What causes Jest "jest-haste-map: duplicate manual mock found" / naming collision?
There are 2 common causes: a build output copy is scanned alongside the source and two manual mocks for the same module. A dist/build/coverage folder contains a copied package.json (or duplicated modules).
How do I fix Jest "jest-haste-map: duplicate manual mock found" / naming collision?
There are 2 fixes depending on which cause you have: ignore build output in modulepathignorepatterns and resolve duplicate manual mocks. Work through them in order, since the first is the most common.
What does Jest "jest-haste-map: duplicate manual mock found" / naming collision actually mean?
Jest prints "jest-haste-map: Haste module naming collision" (or "duplicate manual mock found") listing two file paths that share a name.
How do I stop Jest "jest-haste-map: duplicate manual mock found" / naming collision happening again?
Add dist/build/coverage to modulePathIgnorePatterns. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card