vitest-dev/vitest · error
"Istanbul" coverage provider is not compatible with…
Error message
"Istanbul" coverage provider is not compatible with "experimental.viteModuleRunner: false". Please, enable "viteModuleRunner" or switch to "v8" coverage provider.
What it means
The Istanbul coverage provider instruments code through its own transform pipeline and depends on Vitest's Vite module runner to load the instrumented output. Disabling the experimental module runner (`experimental.viteModuleRunner: false`) breaks that pipeline, so Vitest refuses the pairing rather than emitting silently-wrong coverage.
Solutions
- Switch coverage to `provider: 'v8'`.
- Or remove `experimental.viteModuleRunner: false` (let it default / set it true) and keep Istanbul.
- If you must disable the runner for other reasons, accept v8 coverage for those runs.
Example fix
// before
test: {
coverage: { provider: 'istanbul' },
experimental: { viteModuleRunner: false },
}
// after
test: {
coverage: { provider: 'v8' },
experimental: { viteModuleRunner: false },
} Defensive patterns
Strategy: validation
Validate before calling
if (config.test?.coverage?.provider === 'istanbul' && config.test?.experimental?.viteModuleRunner === false) {
throw new Error('Istanbul coverage requires viteModuleRunner; switching to v8.')
}
config.test.coverage.provider = 'v8' Type guard
function isCompatibleCoverageCombo(provider: string, runner?: boolean): boolean {
return !(provider === 'istanbul' && runner === false)
} Prevention
- When you disable `viteModuleRunner`, audit coverage provider in the same change.
- Document the pairing in the config comment.
When it happens
Trigger: Setting `coverage.provider: 'istanbul'` together with `experimental.viteModuleRunner: false` in the same config.
Common situations: Opting out of the experimental runner for a stability reason while leaving Istanbul as the default coverage provider.
Related errors
- All browser instances within a project must use the same…
- "browser.instances" was set in the config, but the array is…
- Custom CoverageProviderModule loaded from
- Each tag defined in "test.tags" must have a "name"…
- Environment " " is not a valid environment. Path " " should…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/d8004f0d5e1199a1.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/node/config/resolveConfig.ts:480
// if `instances` were defined, but now they are empty,
// let's throw an error because the filter is invalid
if (!browser.instances.length) {
throw new Error([
`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`,
` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map(c => c.browser).join(', ')}). Did you mean to use another name?`,
].join(''))
}
}
browser.instances.forEach((instance) => {
instance.name ??= resolved.name
? `${resolved.name} (${instance.browser})`
: instance.browser
})
}
if (resolved.coverage.enabled && resolved.coverage.provider === 'istanbul' && resolved.experimental?.viteModuleRunner === false) {
throw new Error(`"Istanbul" coverage provider is not compatible with "experimental.viteModuleRunner: false". Please, enable "viteModuleRunner" or switch to "v8" coverage provider.`)
}
if (browser.enabled && resolved.detectAsyncLeaks) {
logger.console.warn(c.yellow('The option "detectAsyncLeaks" is not supported in browser mode and will be ignored.'))
}
resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter)
if (isAgent) {
// default to `skipFull` and add `text-summary` reporter when `text` reporter is used on agents
const text = resolved.coverage.reporter.find(([name]) => name === 'text')
const textSummary = resolved.coverage.reporter.find(([name]) => name === 'text-summary')
if (text) {
(text as any)[1] = { skipFull: true, ...text[1] as any }
if (!textSummary) {
resolved.coverage.reporter.push(['text-summary', {}])
}
}
}View on GitHub (pinned to 1fa9837ec2)