vitest-dev/vitest · error · Error

invalid diff config file ${config.diff}. Must have a default

Error message

invalid diff config file ${config.diff}. Must have a default export with config object

What it means

Thrown by loadDiffConfig when `config.diff` is a string (treated as a path to a diff-options module) but the imported module's `default` export is not a non-null object. Vitest uses this object as SerializedDiffOptions for rendering equality diffs in assertion failures.

Source

Thrown at packages/vitest/src/runtime/setup-common.ts:58

): Promise<SerializedDiffOptions | undefined> {
  if (typeof config.diff === 'object') {
    return config.diff
  }
  if (typeof config.diff !== 'string') {
    return
  }

  const diffModule = await moduleRunner.import(config.diff)

  if (
    diffModule
    && typeof diffModule.default === 'object'
    && diffModule.default != null
  ) {
    return diffModule.default as DiffOptions
  }
  else {
    throw new Error(
      `invalid diff config file ${config.diff}. Must have a default export with config object`,
    )
  }
}

export async function loadSnapshotSerializers(
  config: SerializedConfig,
  moduleRunner: PublicModuleRunner,
): Promise<void> {
  const files = config.snapshotSerializers

  const snapshotSerializers = await Promise.all(
    files.map(async (file) => {
      const mo = await moduleRunner.import(file)
      if (!mo || typeof mo.default !== 'object' || mo.default === null) {
        throw new Error(
          `invalid snapshot serializer file ${file}. Must export a default object`,
        )

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Make the diff config file use `export default { ... }` with the diff option keys.
  2. Or pass the diff options inline as an object instead of a file path: `test: { diff: { aAnnotation: '...' } }`.
  3. Verify the file path in `config.diff` actually points to the diff config and not another module.
  4. If you no longer need a custom diff, remove the `diff` setting to use defaults.

Example fix

// before (./diff.config.js)
export const diffOptions = { aAnnotation: 'Expected' }
// vitest.config
test: { diff: './diff.config.js' }

// after
export default { aAnnotation: 'Expected', bAnnotation: 'Received' }
Defensive patterns

Strategy: type-guard

Validate before calling

import * as diffMod from './diff.config.js'
if (!diffMod.default || typeof diffMod.default !== 'object') {
  throw new Error('diff config must `export default { ... }`')
}

Type guard

function isDiffOptions(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null
}

Prevention

When it happens

Trigger: Setting `test.diff: './diff.config.js'` where that file has no default export, exports default as a function/primitive, or exports default null. The module is evaluated but diffModule.default is missing or not an object.

Common situations: Providing an inline diff config object works (diff: { ... }), but switching to a file path and forgetting the default export. Reusing a vite-style config that uses named exports. TS file whose default is typed but the build stripped it.

Related errors


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