vitest-dev / vitest-dev/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
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 17.1k
- Forks
- 2k
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 94
Description
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:
vi.mocksilently 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- 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: falsea file receives another file'svi.mockthrough 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.mockleak. 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 madevi.mockmiss; 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
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
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
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Begin with the provided two-project configuration, focusing on the vmThreads project, isolate:false, deps.optimizer, and the shared cacheDir plugin. Re-run the frontend suite with optimizer enabled, per-project cache directories, a shared cache directory, and optimizer disabled, then compare the shifting vi.mock and instanceof failures. Done means identifying the remaining module-identity cause or producing a minimal reproduction that isolates it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript, vite
- Domain
- build-system, devtools, testing-qa
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 28/100