vitest-dev/vitest · error · Error
invalid diff config file
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 (a file path) but the imported module's default export is not a non-null object. The diff config customizes how assertion diffs are rendered; when provided as a file path it must default-export a DiffOptions object.
Solutions
- Default-export a DiffOptions object: `export default { aColor: undefined, bColor: undefined }` (or your chosen keys).
- If you only need static options, set `diff` to an object directly in vitest config instead of a file path (loadDiffConfig returns object configs as-is).
- Verify the path in `config.diff` resolves to the intended file.
- Remove the `diff` option entirely to use defaults.
Example fix
// before — diff-config.ts
export const diff = { aAnnotation: 'expected' }
// after
export default { aAnnotation: 'expected' } Defensive patterns
Strategy: type-guard
Validate before calling
async function loadDiff(path: string) {
const mod = await import(/* @vite-ignore */ path)
if (!mod?.default || typeof mod.default !== 'object') {
throw new TypeError(`${path} must default-export a DiffOptions object`)
}
return mod.default
} Type guard
function isDiffOptions(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null
} Prevention
- Prefer passing `diff` as an inline object in config when options are static.
- Use `export default { ... }` and nothing else in a diff config file.
- Keep diff config files minimal and dedicated (no side effects).
When it happens
Trigger: Setting `diff: './diff-config.ts'` in vitest config where that file has no default export, exports a primitive/function as default, or exports the config as a named export only.
Common situations: Authoring a diff config and forgetting `export default`; exporting a function instead of an object; typo in the file path; using a named export by habit.
Related errors
- invalid snapshot serializer file
- All browser instances within a project must use the same…
- "browser.instances" was set in the config, but the array is…
- Custom reporter loaded from
- Each tag defined in "test.tags" must have a "name"…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/8dd63f098df194cb.
Report an issue: GitHub.
Appendix: 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 1fa9837ec2)