{"record":{"id":"5a48f2212e6ebcaf","repo":"vitest-dev/vitest","slug":"the-vcsprovider-module-vcsprovider-doesn-t-ha","errorCode":null,"errorMessage":"The vcsProvider module '${vcsProvider}' doesn't have a default export with `findChangedFiles` method.","messagePattern":"The vcsProvider module '(.+?)' doesn't have a default export with `findChangedFiles` method\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/vcs/vcs.ts","lineNumber":24,"sourceCode":"  root: string\n  changedSince?: string | boolean\n}\n\nexport interface VCSProvider {\n  // eslint-disable-next-line ts/method-signature-style\n  findChangedFiles(options: VCSProviderOptions): Promise<string[]>\n}\n\nexport async function loadVCSProvider(runner: ModuleRunner, vcsProvider: string | VCSProvider | undefined): Promise<VCSProvider> {\n  if (typeof vcsProvider === 'object' && vcsProvider != null) {\n    return wrapVCSProvider(vcsProvider)\n  }\n  if (!vcsProvider || vcsProvider === 'git') {\n    return new GitVCSProvider()\n  }\n  const module = await runner.import(vcsProvider) as { default: VCSProvider }\n  if (!module.default || typeof module.default !== 'object' || typeof module.default.findChangedFiles !== 'function') {\n    throw new Error(`The vcsProvider module '${vcsProvider}' doesn't have a default export with \\`findChangedFiles\\` method.`)\n  }\n  return wrapVCSProvider(module.default)\n}\n\nfunction wrapVCSProvider(provider: VCSProvider): VCSProvider {\n  return {\n    async findChangedFiles(options) {\n      const changedFiles = await provider.findChangedFiles(options)\n      return changedFiles.map(file => resolve(options.root, file))\n    },\n  }\n}\n","sourceCodeStart":6,"sourceCodeEnd":37,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/node/vcs/vcs.ts#L6-L37","documentation":"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.","triggerScenarios":"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'`.","commonSituations":"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()`.","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."],"exampleFix":"// before - my-vcs.ts\nexport function findChangedFiles(options) { return [] }\n\n// after\nexport default {\n  async findChangedFiles(options) {\n    // options.root, options.changedSince\n    return []\n  },\n}","handlingStrategy":"type-guard","validationCode":"import('./my-vcs.ts').then(m => {\n  const ok = m.default != null\n    && typeof m.default === 'object'\n    && typeof m.default.findChangedFiles === 'function'\n  if (!ok) throw new Error('provider missing default.findChangedFiles')\n})","typeGuard":"function isVCSProvider(v: unknown): v is { findChangedFiles(o: { root: string; changedSince?: string | boolean }): Promise<string[]> } {\n  return v != null && typeof v === 'object' && typeof (v as any).findChangedFiles === 'function'\n}","tryCatchPattern":"try { await loadVCSProvider(runner, './my-vcs') } catch (e) { if (/default export/.test(String(e.message))) { /* fix provider module */ } else throw e }","preventionTips":["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'`."],"tags":["vcs","configuration","plugin-api","default-export"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}