{"id":"8bfec209d43e12de","repo":"vitest-dev/vitest","slug":"custom-reporter-loaded-from-path-was-not-the-de","errorCode":null,"errorMessage":"Custom reporter loaded from ${path} was not the default export","messagePattern":"Custom reporter loaded from (.+?) was not the default export","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/reporters/utils.ts","lineNumber":27,"sourceCode":"async function loadCustomReporterModule<C extends Reporter>(\n  path: string,\n  runner: ModuleRunner,\n): Promise<new (options?: unknown) => C> {\n  let customReporterModule: { default: new () => C }\n  try {\n    customReporterModule = await runner.import(path)\n  }\n  catch (customReporterModuleError) {\n    throw new Error(`Failed to load custom Reporter from ${path}`, {\n      cause: customReporterModuleError as Error,\n    })\n  }\n\n  if (\n    customReporterModule.default === null\n    || customReporterModule.default === undefined\n  ) {\n    throw new Error(\n      `Custom reporter loaded from ${path} was not the default export`,\n    )\n  }\n\n  return customReporterModule.default\n}\n\nfunction createReporters(\n  reporterReferences: ResolvedConfig['reporters'],\n  ctx: Vitest,\n): Promise<Array<Reporter | DefaultReporter | BlobReporter | DotReporter | JsonReporter | TapReporter | JUnitReporter | HangingProcessReporter | GithubActionsReporter>> {\n  const runner = ctx.runner\n  const promisedReporters = reporterReferences.map(\n    async (referenceOrInstance) => {\n      if (Array.isArray(referenceOrInstance)) {\n        const [reporterName, reporterOptions] = referenceOrInstance\n\n        if (reporterName === 'html') {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/node/reporters/utils.ts#L9-L45","documentation":"Thrown by `loadCustomReporterModule` (utils.ts:27) when the custom reporter module imports successfully but has no `default` export (`customReporterModule.default` is null/undefined). Vitest requires the reporter constructor to be the default export so it can do `new CustomReporter(options)`; a named-only export or a side-effect-only module is rejected.","triggerScenarios":"Writing a reporter with only a named export (e.g. `export class MyReporter`) and no `export default`; a reporter module whose default export was tree-shaken or is conditionally undefined; importing a utility module instead of the reporter module.","commonSituations":"Forgetting the `default` keyword when authoring a custom reporter; refactoring that moved the class to a named export; pointing at the wrong entry file of a multi-file reporter package.","solutions":["Add `export default` to the reporter class/function in the module.","Confirm the configured path points to the file that actually has the default export.","If loading from a package, check the package's entry exports a default."],"exampleFix":"// before\nexport class MyReporter implements Reporter { /* ... */ }\n// after\nexport default class MyReporter implements Reporter { /* ... */ }","handlingStrategy":"validation","validationCode":"const mod = await import(reporterPath)\nif (mod.default == null || typeof mod.default !== 'function') {\n  throw new Error(`${reporterPath} must have a default export constructor`)\n}","typeGuard":"const hasDefaultReporter = (m: Record<string, unknown>): m is { default: new (o?: unknown) => any } =>\n  typeof m.default === 'function'","tryCatchPattern":null,"preventionTips":["Always author custom reporters with `export default class`.","Lint/CI-check that reporter modules have a default export.","Point the config at the file containing the default export."],"tags":["reporter","custom-reporter","default-export","config"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}