vitest-dev/vitest · error · Error
Failed to load custom CoverageProviderModule from ${options.
Error message
Failed to load custom CoverageProviderModule from ${options.customProviderModule} What it means
When provider is 'custom', Vitest dynamically imports options.customProviderModule via the runtime loader (coverage.ts:86-94). If that import rejects — module not found, syntax error, or the module throws on load — the original error is wrapped (with cause) into this message naming the configured module path.
Source
Thrown at packages/vitest/src/utils/coverage.ts:90
? await loader.import(builtInModule)
: await import(/* @vite-ignore */ builtInModule)
if (!coverageModule) {
throw new Error(
`Failed to load ${CoverageProviderMap[provider]}. Default export is missing.`,
)
}
return coverageModule
}
let customProviderModule
try {
customProviderModule = await loader.import(options.customProviderModule!)
}
catch (error) {
throw new Error(
`Failed to load custom CoverageProviderModule from ${options.customProviderModule}`,
{ cause: error },
)
}
if (customProviderModule.default == null) {
throw new Error(
`Custom CoverageProviderModule loaded from ${options.customProviderModule} was not the default export`,
)
}
return customProviderModule.default
}
View on GitHub (pinned to d568f8ce37)
Solutions
- Verify the customProviderModule path resolves from the project root (try importing it from a script).
- Inspect error.cause for the underlying module-load failure (missing dep, syntax error).
- Install any dependency the custom provider module imports.
- Ensure the module is valid for the current ESM/CJS context.
Example fix
// before: path typo
export default defineConfig({
test: { coverage: { provider: 'custom', customProviderModule: './cov/provider.ts' } },
})
// after: correct existing path
export default defineConfig({
test: { coverage: { provider: 'custom', customProviderModule: './coverage/provider.ts' } },
}) Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'node:fs'
import { resolve } from 'node:path'
function assertCustomProviderPath(root: string, modulePath: string) {
const resolved = resolve(root, modulePath)
if (!existsSync(resolved)) {
throw new Error(`customProviderModule not found at '${resolved}'`)
}
} Try / catch
try {
await resolveCoverageProviderModule(config.coverage, loader)
} catch (e) {
const cause = (e as Error & { cause?: Error }).cause
console.error('Custom coverage provider failed to load:', cause?.message ?? e)
throw e
} Prevention
- Point customProviderModule at a file that exists and imports cleanly.
- Install every dependency the custom provider needs.
- Test-import the module in isolation before wiring it into coverage config.
When it happens
Trigger: Configuring coverage.provider: 'custom' and coverage.customProviderModule: '<path>' where the path is wrong, the file is not valid JS/TS, or the module throws during top-level evaluation. The loader.import call rejects and is caught.
Common situations: Typo in the customProviderModule path; pointing at a file that no longer exists after a refactor; the custom provider module imports a dependency that is not installed; ESM/CJS interop error when loading the module.
Related errors
- Custom CoverageProviderModule loaded from ${options.customPr
- "Istanbul" coverage provider is not compatible with "experim
- You cannot set "coverage.reportsDirectory" as ${reportsDirec
- Missing configurationFile. The "coverage.thresholds.autoUpda
- Expected config.test.coverage.thresholds to be an object
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/124aa4963bd33c17.json.
Report an issue: GitHub.