Summary
Adding react-doctor as a workspace devDependency in a pnpm monorepo can cause Vitest to fail at test collection with:
Error: Vitest failed to find the current suite.
...
❯ afterEach tests/*.ts:18
This is not a test-logic bug. The same test files pass when react-doctor is not installed.
Environment
- react-doctor:
0.3.0
- Package manager: pnpm
11.2.2 (workspace)
- Toolchain: Vite+ (
vite-plus@0.1.22)
- Vitest: aliased to
@voidzero-dev/vite-plus-test@0.1.22 via workspace catalog
- Test runner:
@cloudflare/vitest-pool-workers@0.16.11
- Monorepo layout: root +
apps/engine, apps/website, packages/*
- Tests import:
import { afterEach, ... } from 'vite-plus/test' (re-exports vitest)
Root cause (pnpm dependency graph)
react-doctor@0.3.0 depends on oxlint (not just oxlint-plugin-react-doctor).
That introduces a second physical install of the same Vitest fork (@voidzero-dev/vite-plus-test@0.1.22) with a different peer-dependency fingerprint:
@voidzero-dev/vite-plus-test@0.1.22 peer#61d8 → engine/website vitest graph
@voidzero-dev/vite-plus-test@0.1.22 peer#77ec → root packages via react-doctor → oxlint → vite-plus
pnpm why @voidzero-dev/vite-plus-test reports: Found 1 version, 2 instances.
At runtime:
- Vitest CLI / runner resolves one instance (e.g. via
apps/engine/node_modules/vitest)
- Test files import hooks from
vite-plus/test, which re-exports from a different instance (via a vite-plus install tied to the oxlint/react-doctor subgraph)
afterEach() then registers on instance A while the active suite lives on instance B → collection fails before any test runs.
Reproduction
-
pnpm workspace using Vite+ catalog:
catalogs:
viteplus:
vitest: npm:@voidzero-dev/vite-plus-test@0.1.22
vite: npm:@voidzero-dev/vite-plus-core@0.1.22
vite-plus: 0.1.22
overrides:
vitest: catalog:viteplus
-
apps/engine (or similar) with:
vitest: catalog:viteplus
@cloudflare/vitest-pool-workers
- test files using
import { afterEach } from 'vite-plus/test'
-
Add to root package.json:
"devDependencies": {
"react-doctor": "0.3.0"
}
-
pnpm install
-
Run tests from workspace root:
vp run engine#test
# or: vp run -r test
-
Observe all suites fail at collection with Vitest failed to find the current suite on top-level afterEach.
-
Remove react-doctor from root deps → pnpm install → tests pass again.
Why pnpm.overrides alone does not fix it
We already had:
overrides:
vitest: catalog:viteplus
Overrides force the package identity everywhere, but pnpm still creates multiple physical installs when peer contexts differ. Vitest’s hook registry is per module instance, so duplicates still break.
Workarounds we found (consumer-side)
| Approach |
Result |
Remove react-doctor from workspace deps; use vp dlx react-doctor@0.3.0 |
Avoids graph split, but loses import type { ReactDoctorConfig } from 'react-doctor/api' without a separate types story |
peerDependencyRules.allowedVersions.vitest: npm:@voidzero-dev/vite-plus-test@0.1.22 |
Sometimes collapses to 1 instance (fragile; still 2 instances observed after reinstall with react-doctor) |
dedupePeerDependents: true |
Helps but not sufficient alone |
Suggested directions for react-doctor
- Document that installing
react-doctor pulls oxlint and may duplicate Vitest/Vite+ installs in strict pnpm monorepos using catalog aliases.
- Consider
oxlint as optional peer or not bundling oxlint when consumers already use Vite+/oxlint via workspace tooling.
- Consider publishing
react-doctor/api types separately (or documenting a types-only import path) so consumers can run the CLI via dlx without installing the full package graph.
- Add a monorepo / pnpm troubleshooting note for Vitest +
vite-plus/test import pattern.
Happy to provide a minimal reproduction repo if useful.
Summary
Adding
react-doctoras a workspace devDependency in a pnpm monorepo can cause Vitest to fail at test collection with:This is not a test-logic bug. The same test files pass when
react-doctoris not installed.Environment
0.3.011.2.2(workspace)vite-plus@0.1.22)@voidzero-dev/vite-plus-test@0.1.22via workspace catalog@cloudflare/vitest-pool-workers@0.16.11apps/engine,apps/website,packages/*import { afterEach, ... } from 'vite-plus/test'(re-exports vitest)Root cause (pnpm dependency graph)
react-doctor@0.3.0depends onoxlint(not justoxlint-plugin-react-doctor).That introduces a second physical install of the same Vitest fork (
@voidzero-dev/vite-plus-test@0.1.22) with a different peer-dependency fingerprint:pnpm why @voidzero-dev/vite-plus-testreports: Found 1 version, 2 instances.At runtime:
apps/engine/node_modules/vitest)vite-plus/test, which re-exports from a different instance (via avite-plusinstall tied to the oxlint/react-doctor subgraph)afterEach()then registers on instance A while the active suite lives on instance B → collection fails before any test runs.Reproduction
pnpm workspace using Vite+ catalog:
apps/engine(or similar) with:vitest: catalog:viteplus@cloudflare/vitest-pool-workersimport { afterEach } from 'vite-plus/test'Add to root
package.json:pnpm installRun tests from workspace root:
vp run engine#test # or: vp run -r testObserve all suites fail at collection with
Vitest failed to find the current suiteon top-levelafterEach.Remove
react-doctorfrom root deps →pnpm install→ tests pass again.Why
pnpm.overridesalone does not fix itWe already had:
Overrides force the package identity everywhere, but pnpm still creates multiple physical installs when peer contexts differ. Vitest’s hook registry is per module instance, so duplicates still break.
Workarounds we found (consumer-side)
react-doctorfrom workspace deps; usevp dlx react-doctor@0.3.0import type { ReactDoctorConfig } from 'react-doctor/api'without a separate types storypeerDependencyRules.allowedVersions.vitest: npm:@voidzero-dev/vite-plus-test@0.1.22dedupePeerDependents: trueSuggested directions for react-doctor
react-doctorpullsoxlintand may duplicate Vitest/Vite+ installs in strict pnpm monorepos using catalog aliases.oxlintas optional peer or not bundling oxlint when consumers already use Vite+/oxlint via workspace tooling.react-doctor/apitypes separately (or documenting a types-only import path) so consumers can run the CLI viadlxwithout installing the full package graph.vite-plus/testimport pattern.Happy to provide a minimal reproduction repo if useful.