vitest-dev/vitest · error · Error

Failed to load custom Reporter from

Error message

Failed to load custom Reporter from ${path}

What it means

Vitest tried to dynamically import the custom reporter module at `path` and the import itself threw (module not found, syntax error, top-level throw, unsupported ESM/CJS). The original error is attached as `cause` so the real reason is preserved; this outer message only identifies which reporter path failed.

Solutions

  1. Inspect `error.cause` for the underlying module error (the real message).
  2. Confirm the path resolves from the project root (Vitest resolves it via the module runner).
  3. Reproduce the import standalone: `node -e "import('./path').then(console.log).catch(console.error)"`.
  4. Fix the missing dependency / syntax error / interop issue inside the reporter module.

Example fix

// inspecting the cause
try {
  await startVitest('test', [], {}, { reporters: [['./my-reporter.js', {}]] })
} catch (e) {
  console.error(e.message)        // 'Failed to load custom Reporter from ./my-reporter.js'
  console.error(e.cause)          // real error, e.g. Cannot find module 'pino'
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { pathToFileURL } from 'node:url'
// Pre-validate that the reporter module is importable from the project root.
async function assertReporterImportable(path: string) {
  await import(pathToFileURL(resolve(process.cwd(), path)).href)
}

Try / catch

try {
  await startVitest('test', [], {}, { reporters: [[reporterPath, {}]] })
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Failed to load custom Reporter from ')) {
    console.error('Underlying import error:', e.cause)
    // fix the module, then retry
  }
  throw e
}

Prevention

When it happens

Trigger: `reporters: [['./wrong-path.js', {}]]` or any non-builtin reporter name that resolves to a module that errors on import; `loadCustomReporterModule` catches the import rejection and re-throws wrapped.

Common situations: Typo in the reporter path; missing dependency imported by the reporter; ESM/CJS interop failure; reporter file has a syntax error or throws at module top level.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/c48cce2c2810e60b. Report an issue: GitHub.

Appendix: source

Thrown at packages/vitest/src/node/reporters/utils.ts:18

import type { ModuleRunner } from 'vite/module-runner'
import type { Vitest } from '../core'
import type { ResolvedConfig } from '../types/config'
import type { Reporter } from '../types/reporter'
import type { BlobReporter } from './blob'
import type { BuiltinReporters, DefaultReporter, DotReporter, GithubActionsReporter, HangingProcessReporter, JsonReporter, JUnitReporter, TapReporter } from './index'
import { ReportersMap } from './index'

async function loadCustomReporterModule<C extends Reporter>(
  path: string,
  runner: ModuleRunner,
): Promise<new (options?: unknown) => C> {
  let customReporterModule: { default: new () => C }
  try {
    customReporterModule = await runner.import(path)
  }
  catch (customReporterModuleError) {
    throw new Error(`Failed to load custom Reporter from ${path}`, {
      cause: customReporterModuleError as Error,
    })
  }

  if (
    customReporterModule.default === null
    || customReporterModule.default === undefined
  ) {
    throw new Error(
      `Custom reporter loaded from ${path} was not the default export`,
    )
  }

  return customReporterModule.default
}

function createReporters(
  reporterReferences: ResolvedConfig['reporters'],

View on GitHub (pinned to 1fa9837ec2)