vitest-dev/vitest · error · Error
The vcsProvider module
Error message
The vcsProvider module '${vcsProvider}' doesn't have a default export with `findChangedFiles` method. What it means
Vitest allows a custom VCS provider via the `vcsProvider` config option (a module specifier string). After dynamically importing that module, Vitest requires its `default` export to be an object exposing a `findChangedFiles` function. This error fires when the module loads but its default export is missing, not an object, or lacks the required method — i.e. the module does not conform to the `VCSProvider` interface.
Solutions
- Ensure the provider module has `export default { async findChangedFiles(options) { ... } }` returning absolute or root-relative file paths.
- Verify the method name is exactly `findChangedFiles` (not `getChangedFiles`/`changedFiles`) and is async returning `Promise<string[]>`.
- If you only need git, omit `vcsProvider` or set it to `'git'` to use the built-in GitVCSProvider.
- Pass a ready-made object instead of a module string: `vcsProvider: { findChangedFiles: async (opts) => [...] }` to bypass module loading entirely.
Example fix
// before - my-vcs.ts
export function findChangedFiles(options) { return [] }
// after
export default {
async findChangedFiles(options) {
// options.root, options.changedSince
return []
},
} Defensive patterns
Strategy: type-guard
Validate before calling
import('./my-vcs.ts').then(m => {
const ok = m.default != null
&& typeof m.default === 'object'
&& typeof m.default.findChangedFiles === 'function'
if (!ok) throw new Error('provider missing default.findChangedFiles')
}) Type guard
function isVCSProvider(v: unknown): v is { findChangedFiles(o: { root: string; changedSince?: string | boolean }): Promise<string[]> } {
return v != null && typeof v === 'object' && typeof (v as any).findChangedFiles === 'function'
} Try / catch
try { await loadVCSProvider(runner, './my-vcs') } catch (e) { if (/default export/.test(String(e.message))) { /* fix provider module */ } else throw e } Prevention
- Author the provider against the exported `VCSProvider` interface from `vitest/node`.
- Prefer passing a ready object (`vcsProvider: { findChangedFiles }`) over a module string to get compile-time checking.
- Add a unit test that imports the provider and asserts `typeof default.findChangedFiles === 'function'`.
When it happens
Trigger: Setting `vcsProvider: './my-vcs'` (or `vcs: { provider: './my-vcs' }`) where the resolved module has no default export, exports a primitive/function as default, or the default object has no `findChangedFiles(options)` method. The check at vcs.ts:23 explicitly tests `!module.default || typeof module.default !== 'object' || typeof module.default.findChangedFiles !== 'function'`.
Common situations: Authoring a custom VCS provider for a non-git VCS (Mercurial, Perforce, SVN) and forgetting the default export; naming the method `getChangedFiles` instead of `findChangedFiles`; exporting a class instance whose prototype carries the method but the static default is a config object; pointing `vcsProvider` at a re-export barrel file that does `export { GitVCSProvider }` instead of `export default new GitVCSProvider()`.
Related errors
- Benchmark provider loaded from
- Cannot use the `bench` test-context fixture within a…
- Custom CoverageProviderModule loaded from
- Failed to import custom OpenTelemetry SDK script
- Failed to load benchmark provider from
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/5a48f2212e6ebcaf.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/node/vcs/vcs.ts:24
root: string
changedSince?: string | boolean
}
export interface VCSProvider {
// eslint-disable-next-line ts/method-signature-style
findChangedFiles(options: VCSProviderOptions): Promise<string[]>
}
export async function loadVCSProvider(runner: ModuleRunner, vcsProvider: string | VCSProvider | undefined): Promise<VCSProvider> {
if (typeof vcsProvider === 'object' && vcsProvider != null) {
return wrapVCSProvider(vcsProvider)
}
if (!vcsProvider || vcsProvider === 'git') {
return new GitVCSProvider()
}
const module = await runner.import(vcsProvider) as { default: VCSProvider }
if (!module.default || typeof module.default !== 'object' || typeof module.default.findChangedFiles !== 'function') {
throw new Error(`The vcsProvider module '${vcsProvider}' doesn't have a default export with \`findChangedFiles\` method.`)
}
return wrapVCSProvider(module.default)
}
function wrapVCSProvider(provider: VCSProvider): VCSProvider {
return {
async findChangedFiles(options) {
const changedFiles = await provider.findChangedFiles(options)
return changedFiles.map(file => resolve(options.root, file))
},
}
}
View on GitHub (pinned to 1fa9837ec2)