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
- Make the diff config file use `export default { ... }` with the diff option keys.
- Or pass the diff options inline as an object instead of a file path: `test: { diff: { aAnnotation: '...' } }`.
- Verify the file path in `config.diff` actually points to the diff config and not another module.
- 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
- Prefer inline diff config object unless you need to share it across files.
- Always use `export default { ... }` in a diff config file.
- Add a unit test importing the diff config to catch export mistakes.
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
- Runner must export a default function, but got ${typeof mod.
- invalid snapshot serializer file ${file}. Must export a defa
- Failed to import custom OpenTelemetry SDK script (${options.
- You've enabled headless mode for "preview" provider but it d
- vitest/browser can be imported only inside the Browser Mode.
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/8dd63f098df194cb.json.
Report an issue: GitHub.