vitest-dev/vitest · error · Error

${error instanceof Error ? error.message : String(error)}

Error message

${error instanceof Error ? error.message : String(error)}

What it means

resolveConfig (coverage.ts:900) catches magicast errors while statically analyzing the config AST and rethrows just the message. This is the generic fallback for any unparseable shape while walking defineConfig/mergeConfig/inline-object forms during the autoUpdate flow.

Source

Thrown at packages/vitest/src/node/coverage.ts:900

    }

    // "export default defineConfig(...)"
    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

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Simplify the config so thresholds sit inside a plain export default defineConfig({ test: { coverage: { thresholds: {...} } } }).
  2. Move dynamic logic out of the config file (env-based branching, etc.).
  3. Disable autoUpdate and update thresholds manually if the config must stay dynamic.

Example fix

// before
export default defineConfig(() => buildConfig(env))

// after
export default defineConfig({ test: { coverage: { thresholds: { lines: 80 } } } })
Defensive patterns

Strategy: fallback

Validate before calling

try {
  await reporter.updateThresholds(...)
} catch (e) {
  console.warn('Static config rewrite failed; falling back to manual thresholds')
}

Type guard

function isStaticallyParseable(ast: any): boolean {
  return ast?.exports?.default?.$type === 'object'
    || ast?.exports?.default?.$callee === 'defineConfig'
    || ast?.exports?.default?.$callee === 'mergeConfig'
}

Try / catch

try { resolveConfig(mod) }
catch (e) { throw new Error(`Config too dynamic to rewrite thresholds: ${(e as Error).message}`) }

Prevention

When it happens

Trigger: A config file whose AST magicast cannot statically resolve — computed property keys, dynamic imports, runtime-spread conditionals, calls to unknown helper functions.

Common situations: Highly dynamic config files; configs that wrap defineConfig in custom helpers; configs that build the test object conditionally at runtime.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/d73076eb59571ae9.json. Report an issue: GitHub.