#11289·vitest

vmThreads + isolate:false + deps.optimizer: vi.mock misses and duplicate module identity — green on 4.1.11, flaky every run on 5.0.1

Author: MO2k4Created Sep 16, 2026Updated Sep 16, 2026

Describe the bug

On a large monorepo suite (~300 files, ~3900 tests) that runs pool: 'vmThreads' with deps.optimizer enabled, upgrading 4.1.11 → 5.0.1 turns a deterministically green suite into one that fails a different set of tests on every run. The same config on 4.1.11 is green 3/3.

Two distinct symptom shapes, both pointing at module identity rather than test logic:

  1. vi.mock silently does not apply — the real module is used instead, with no error:
    AssertionError: expected "vi.fn()" to be called 1 times, but got 0 times
  2. Duplicate module instances — the same class reached through two different module instances:
    AssertionError: expected AppError: Etwas ist schiefgelaufen {...} to be an instance of AppError

Both are confined to the vmThreads project (isolate: false, which vm pools force). A sibling project on pool: 'forks' with isolation is green on both versions. Our backend integration suite shows the same signature: ~30 files fail, all in the isolate: false project, with membership shifting between runs.

A/B, identical config, same machine

Frontend workspace, both projects, 3 consecutive runs each:

vitest result
4.1.11 3/3 green — 299 files, 3927 tests passed
5.0.1 fails every run — 2 to 18 tests, different set each time

This is the part I would most like to flag: #11284 reports a closely related vmThreads cross-file vi.mock leak and states it is not a v5 regression ("observed on both 4.0.18 and 5.0.1"). For the isolate: false case in this repo that does not hold — 4.1.11 is deterministically green across repeated runs, 5.0.1 is not.

The optimizer / shared cache dir dimension

This is the part I could not find covered in any existing issue.

Two project entries each enable deps.optimizer (client and ssr) over a set of first-party workspace packages, and a small plugin forces both projects' cacheDir to one shared directory (so the prebundle is built once and reused by both).

Failure counts scale with that sharing:

configuration failures per run
parallel-env project alone (forks, isolated) 0
parallel project alone (vmThreads) 2–3, shifting
both projects together, one shared cacheDir 15–18, shifting
both projects, per-project cacheDir 2–7, shifting
both projects, deps.optimizer disabled entirely 0

Disabling deps.optimizer is the only configuration that makes the suite fully green on v5. Cold cache also helps markedly: the first run after deleting node_modules/.vite produced 1 failure, the next run with the now-warm prebundle produced 15.

Stack traces on failing assertions point into prebundled chunks carrying ?v=<hash> query strings, e.g.:

❯ ErrorResponse node_modules/.vite/vitest/first-party/deps_ssr/<pkg>.js?v=124a2a15:1129:25

which is the same module-identity mechanism described in #11193. That one was fixed by #11199 in 5.0.1 and did improve things a lot here (5.0.0 was far worse — 15–19 failures per run even for a single project), but it did not eliminate the problem.

Reproduction

I do not have a minimal reproduction, and I want to be upfront about that rather than file a synthetic one that does not actually reproduce.

I built a scratch project mirroring the config shape — two projects (vmThreads + forks) sharing one optimizer cache dir, a local workspace package in deps.optimizer.include, one file mocking that package, a sibling file asserting instanceof and the real implementation through a shared transitive consumer — and scaled it to 63 files / 124 tests. It stays green across 3 runs on 5.0.1. This matches the experience reported in #11284, where plain multi-file setups did not reproduce either and the trigger needed @vitejs/plugin-react + .tsx + vi.hoisted.

Differences between my scratch project and the real suite that I have not yet isolated: @vitejs/plugin-react and .tsx test files, per-file @vitest-environment jsdom/happy-dom pragmas, a much larger first-party module graph, and custom rolldownOptions (a output.banner cache-buster keyed on first-party source dirs, plus plugins that externalise node builtins and drop sourcemaps).

I am very happy to bisect, run patched builds, or instrument a specific code path against the real suite — it reproduces reliably there within a single run, so turnaround is fast. If it would help, I can also try to carve a shareable reproduction out of the real repo.

Related

  • #11152 — under isolate: false a file receives another file's vi.mock through a shared transitive import. Same project configuration as ours. A maintainer notes one direction is intended (the consumer module is already executed and cached).
  • #11284 — vmThreads cross-file vi.mock leak. Same symptom class; the A/B above is offered as a counterpoint to the "not a v5 regression" assessment.
  • #11193 / #11199 — the ?v=<browserHash> cache staleness that made vi.mock miss; fixed in 5.0.1 and a large improvement here, but not a complete fix.

If maintainers consider this a duplicate of #11152 or #11284, please close it and I will move the A/B data and the optimizer/cacheDir findings into whichever thread is most useful.

Config shape

javascript
const optimizer = { enabled: true, include: [/* first-party workspace pkgs */], exclude: [...],
  rolldownOptions: { platform: 'node', plugins: [/* externalise builtins, drop sourcemaps */],
    output: /* banner cache-buster keyed on first-party source dirs */ } };

export default defineConfig({
  plugins: [sharedPrebundleCacheDirPlugin(__dirname)], // forces both projects to ONE cacheDir
  test: {
    maxWorkers: 4,
    vmMemoryLimit: '512MB',
    deps: { optimizer: { client: { enabled: false }, ssr: { enabled: false } } }, // off at root
    projects: [
      { extends: true, test: { name: 'parallel', pool: 'vmThreads', maxWorkers: 4,
          deps: { optimizer: { client: optimizer, ssr: optimizer } } } },
      { extends: true, test: { name: 'parallel-env', pool: 'forks', maxWorkers: 4,
          deps: { optimizer: { client: optimizer, ssr: optimizer } } } },
    ],
  },
});

System Info

bash
System:
    OS: macOS 26.6.2
    CPU: (12) arm64 Apple M2 Max
    Memory: 9.86 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 24.21.0
    npm: 11.19.0
    bun: 1.4.2
  npmPackages:
    @vitest/coverage-v8: 5.0.1 => 5.0.1
    vitest: 5.0.1 => 5.0.1
    vite: 8.2.2 => 8.2.2

Used Package Manager

bun

Validations