vitest-dev/vitest · error · Error

Runner must implement "importFile" method.

Error message

Runner must implement "importFile" method.

What it means

Thrown by resolveTestRunner after instantiating the (custom or built-in) runner class if the instance has no `importFile` method. importFile is the only strictly required method of the VitestRunner contract — it is how test and setup files are loaded for both collection and execution — so a runner lacking it cannot function.

Solutions

  1. Extend the base runner so importFile is inherited: `export default class MyRunner extends VitestTestRunner { ... }`.
  2. If implementing from scratch, define `importFile(filepath: string, source: 'collect' | 'setup'): unknown` per the VitestRunner interface (types.ts:1733).
  3. Check you did not shadow or delete importFile in a subclass.

Example fix

// before — custom runner missing importFile
export default class MyRunner {
  constructor(config) { this.config = config }
}

// after
import { VitestTestRunner } from 'vitest/runners'
export default class MyRunner extends VitestTestRunner {
  // importFile inherited; add overrides as needed
}
Defensive patterns

Strategy: type-guard

Validate before calling

import type { VitestRunner } from 'vitest/runners'
function assertRunnerShape(Runner: new (c: any) => VitestRunner) {
  const r = new Runner({} as any)
  if (typeof r.importFile !== 'function') {
    throw new TypeError('Custom runner must implement importFile(filepath, source)')
  }
}

Type guard

function hasImportFile(r: unknown): r is { importFile: (f: string, s: 'collect' | 'setup') => unknown } {
  return typeof (r as any)?.importFile === 'function'
}

Prevention

When it happens

Trigger: A custom runner class (set via `config.runner`) that extends VitestTestRunner incorrectly, overrides/omits importFile, or does not extend the base runner and forgets to define importFile. The built-in TestRunner always provides it, so this is only hit with custom runners.

Common situations: Implementing a runner from scratch (not extending VitestTestRunner) and missing importFile; accidentally renaming or deleting importFile while overriding other methods; a runner written against an older Vitest API.

Related errors


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

Appendix: source

Thrown at packages/vitest/src/runtime/runners/index.ts:49

  moduleRunner: TestModuleRunner,
  traces: Traces,
): Promise<VitestRunner> {
  const TestRunner = await getTestRunnerConstructor(config, moduleRunner)
  const testRunner = new TestRunner(config)

  // inject private executor to every runner
  Object.defineProperty(testRunner, 'moduleRunner', {
    value: moduleRunner,
    enumerable: false,
    configurable: false,
  })

  if (!testRunner.config) {
    testRunner.config = config
  }

  if (!testRunner.importFile) {
    throw new Error('Runner must implement "importFile" method.')
  }

  if ('__setTraces' in testRunner) {
    (testRunner.__setTraces as any)(traces)
  }

  const [diffOptions] = await Promise.all([
    loadDiffConfig(config, moduleRunner),
    loadSnapshotSerializers(config, moduleRunner),
  ])
  testRunner.config._diffOptions = diffOptions

  // patch some methods, so custom runners don't need to call RPC
  const originalOnTaskUpdate = testRunner.onTaskUpdate
  testRunner.onTaskUpdate = async (task, events) => {
    const p = rpc().onTaskUpdate(task, events)
    await originalOnTaskUpdate?.call(testRunner, task, events)
    return p

View on GitHub (pinned to 1fa9837ec2)