vitest-dev/vitest · error · Error
Failed to update coverage thresholds. Configuration file is
Error message
Failed to update coverage thresholds. Configuration file is too complex.
What it means
resolveConfig (coverage.ts:903) final fallback: vitest tried inline object, defineConfig(...), and mergeConfig(...) shapes and none matched, so it cannot safely rewrite thresholds. The config is too complex for static rewriting.
Source
Thrown at packages/vitest/src/node/coverage.ts:903
let config = resolveDefineConfig(mod)
if (config) {
return config
}
// "export default mergeConfig(..., defineConfig(...))"
if (mod.$type === 'function-call' && mod.$callee === 'mergeConfig') {
config = resolveMergeConfig(mod)
if (config) {
return config
}
}
}
catch (error) {
// Reduce magicast's verbose errors to readable ones
throw new Error(error instanceof Error ? error.message : String(error))
}
throw new Error(
'Failed to update coverage thresholds. Configuration file is too complex.',
)
}
function resolveDefineConfig(mod: any) {
if (mod.$type === 'function-call' && mod.$callee === 'defineConfig') {
// "export default defineConfig({ test: {...} })"
if (mod.$args[0].$type === 'object') {
return mod.$args[0]
}
if (mod.$args[0].$type === 'arrow-function-expression') {
if (mod.$args[0].$body.$type === 'object') {
// "export default defineConfig(() => ({ test: {...} }))"
return mod.$args[0].$body
}
// "export default defineConfig(() => mergeConfig({...}, ...))"View on GitHub (pinned to d568f8ce37)
Solutions
- Use the standard form: export default defineConfig({ test: { coverage: { thresholds: {...} } } }).
- Disable coverage.thresholds.autoUpdate and update the numbers manually.
- Inline any wrapper so the thresholds object is statically visible to magicast.
Example fix
// before
export default wrapConfig(defineConfig({ test: { coverage: { thresholds: {...} } } }))
// after
export default defineConfig({ test: { coverage: { thresholds: { lines: 80 } } } }) Defensive patterns
Strategy: validation
Validate before calling
const mod = await parseModule(await fs.readFile(cfgPath, 'utf-8'))
const def = mod.exports.default
const ok = def?.$type === 'object'
|| def?.$callee === 'defineConfig'
|| def?.$callee === 'mergeConfig'
if (!ok) throw new Error('Config shape not supported for autoUpdate') Type guard
function isRecognizedConfigShape(def: any): boolean {
return def?.$type === 'object'
|| (def?.$type === 'function-call' && ['defineConfig', 'mergeConfig'].includes(def.$callee))
} Prevention
- Use export default defineConfig({ test: { coverage: { thresholds: {...} } } }) verbatim.
- Don't wrap the config in custom factories when using autoUpdate.
- Disable autoUpdate for configs that must use wrappers.
When it happens
Trigger: Config uses a pattern vitest doesn't recognize — custom wrapper around defineConfig, factory functions, re-exports, or third-party compose helpers — so the AST walker can't find the thresholds node.
Common situations: Shared monorepo config helpers, configs that call defineConfig through indirection, configs built by plugins.
Related errors
- ${error instanceof Error ? error.message : String(error)}
- Missing configurationFile. The "coverage.thresholds.autoUpda
- Unable to parse thresholds from configuration file: ${messag
- BaseReporter's parseConfigModule was not overwritten
- 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/bf8ba6a46952004a.json.
Report an issue: GitHub.