{"id":"8dd63f098df194cb","repo":"vitest-dev/vitest","slug":"invalid-diff-config-file-config-diff-must-have","errorCode":null,"errorMessage":"invalid diff config file ${config.diff}. Must have a default export with config object","messagePattern":"invalid diff config file (.+?)\\. Must have a default export with config object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/setup-common.ts","lineNumber":58,"sourceCode":"): Promise<SerializedDiffOptions | undefined> {\n  if (typeof config.diff === 'object') {\n    return config.diff\n  }\n  if (typeof config.diff !== 'string') {\n    return\n  }\n\n  const diffModule = await moduleRunner.import(config.diff)\n\n  if (\n    diffModule\n    && typeof diffModule.default === 'object'\n    && diffModule.default != null\n  ) {\n    return diffModule.default as DiffOptions\n  }\n  else {\n    throw new Error(\n      `invalid diff config file ${config.diff}. Must have a default export with config object`,\n    )\n  }\n}\n\nexport async function loadSnapshotSerializers(\n  config: SerializedConfig,\n  moduleRunner: PublicModuleRunner,\n): Promise<void> {\n  const files = config.snapshotSerializers\n\n  const snapshotSerializers = await Promise.all(\n    files.map(async (file) => {\n      const mo = await moduleRunner.import(file)\n      if (!mo || typeof mo.default !== 'object' || mo.default === null) {\n        throw new Error(\n          `invalid snapshot serializer file ${file}. Must export a default object`,\n        )","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/runtime/setup-common.ts#L40-L76","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (./diff.config.js)\nexport const diffOptions = { aAnnotation: 'Expected' }\n// vitest.config\ntest: { diff: './diff.config.js' }\n\n// after\nexport default { aAnnotation: 'Expected', bAnnotation: 'Received' }","handlingStrategy":"type-guard","validationCode":"import * as diffMod from './diff.config.js'\nif (!diffMod.default || typeof diffMod.default !== 'object') {\n  throw new Error('diff config must `export default { ... }`')\n}","typeGuard":"function isDiffOptions(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["config","diff","esm"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}