vitest-dev/vitest · error · Error
Runner must implement "importFile" method.
Error message
Runner must implement "importFile" method.
What it means
Thrown by resolveTestRunner after constructing the (possibly custom) runner instance: the resulting object does not have an `importFile` method. importFile is the one mandatory method of a VitestRunner because it is how Vitest loads each test file. Without it no test can run.
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 pView on GitHub (pinned to d568f8ce37)
Solutions
- Implement `importFile(filepath: string)` on your runner class (typically delegating to a vm/vite module loader).
- Extend `VitestRunner` from `vitest/runners` so you inherit a default importFile and only override what you need.
- Confirm the method name spelling is exactly `importFile`.
- After build, check the compiled file exports the class with the method on its prototype.
Example fix
// before
export default class MyRunner extends VitestRunner {
onCollected() { /* ... */ }
// missing importFile
}
// after
export default class MyRunner extends VitestRunner {
async importFile(file) {
return await this.moduleRunner.import(file)
}
} Defensive patterns
Strategy: type-guard
Validate before calling
import MyRunner from './my-runner.js'
const proto = MyRunner.prototype
if (typeof proto.importFile !== 'function') {
throw new Error('Custom runner is missing importFile')
} Type guard
function hasImportFile<R extends new (...a: any[]) => any>(Runner: R): boolean {
return typeof Runner.prototype.importFile === 'function'
} Prevention
- Extend VitestRunner so you inherit importFile unless you override it.
- Add a smoke test that instantiates the runner and asserts importFile exists.
- When overriding, call super or re-implement importFile deliberately.
When it happens
Trigger: A custom runner class (config.runner) that defines other lifecycle hooks (onCollected, onAfterRunTask, etc.) but forgets importFile. A runner class whose prototype chain is broken so importFile from the base class is lost. Extending the wrong base class that does not implement importFile.
Common situations: Implementing a custom runner and overlooking the importFile requirement. Subclassing a non-runner base. Shadowing importFile with `undefined` accidentally.
Related errors
- Environment "${name}" is not a valid environment. Path "${pa
- Tag "${tag.name}": priority must be a non-negative number.
- Unknown value for "test.listTags": ${listTags}
- Expected config.test.coverage.thresholds to be an object
- invalid export in globalSetup file ${file}: ${exp} must be a
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/8360e71660121b10.json.
Report an issue: GitHub.