vitest-dev/vitest · error · Error

The projects glob matched a file "${relative(parentConfig.ro

Error message

The projects glob matched a file "${relative(parentConfig.root, path)}", but it should also either start with "vitest.config"/"vite.config" or match the pattern "(vitest|vite).*.config.*".

What it means

Thrown during project resolution when the `projects` glob in your vitest config matches a filesystem entry that is a plain file but does not look like a Vite/Vitest config file. Vitest validates the file's basename against the regex `/^vite(?:st)?(?:\.[\w-]+)?\.config\./` (defined at resolveProjects.ts:40); only files matching that pattern (e.g. `vitest.config.ts`, `vite.workspace.config.mjs`) are accepted as project configs. Any other matched file aborts resolution because Vitest cannot infer how to load it as a project.

Source

Thrown at packages/vitest/src/node/projects/resolveProjects.ts:1071

    const projectsFs = await glob(projectsGlobMatches, globOptions)

    projectsFs.forEach((path) => {
      // directories are allowed with a glob like `packages/*`
      // in this case every directory is treated as a project
      if (path.endsWith('/')) {
        const configFile = resolveDirectoryConfig(path)
        if (configFile) {
          projectsConfigFiles.push(configFile)
        }
        else {
          nonConfigProjectDirectories.push(path)
        }
      }
      else {
        const name = basename(path)
        if (!CONFIG_REGEXP.test(name)) {
          throw new Error(
            `The projects glob matched a file "${relative(parentConfig.root, path)}", `
            + `but it should also either start with "vitest.config"/"vite.config" `
            + `or match the pattern "(vitest|vite).*.config.*".`,
          )
        }
        projectsConfigFiles.push(path)
      }
    })
  }

  const projectConfigFiles = Array.from(new Set(projectsConfigFiles))

  return {
    projectConfigs: projectsOptions,
    nonConfigDirectories: nonConfigProjectDirectories,
    configFiles: projectConfigFiles,
  }
}

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Change the `projects` glob so it only matches directories (e.g. `packages/*` matched against folders) or config files specifically.
  2. Rename the matched file to follow the `vitest.config.*` / `vite.config.*` / `vitest.<scope>.config.*` convention.
  3. Add more specific ignore patterns or narrow the glob to `**/vitest.config.*` to avoid catching unrelated files.
  4. Delete or relocate the stray non-config file that the glob is matching.

Example fix

// before (vitest.config.ts)
export default defineConfig({
  projects: ['packages/*'] // matches packages/shared.js as a file
})
// after
export default defineConfig({
  projects: ['packages/*/vitest.config.ts']
})
Defensive patterns

Strategy: validation

Validate before calling

import { glob } from 'tinyglobby'
import { basename } from 'node:path'
const CONFIG_REGEXP = /^vite(?:st)?(?:\.[\w-]+)?\.config\./
const matches = await glob(['packages/*'], { cwd: root, absolute: true, onlyFiles: false, dot: true })
const bad = matches.filter(p => !p.endsWith('/') && !CONFIG_REGEXP.test(basename(p)))
if (bad.length) throw new Error(`Non-config files matched by projects glob: ${bad.join(', ')}`)

Type guard

import { basename } from 'node:path'
const CONFIG_REGEXP = /^vite(?:st)?(?:\.[\w-]+)?\.config\./
const isConfigFile = (p: string): boolean => CONFIG_REGEXP.test(basename(p))

Prevention

When it happens

Trigger: Setting `projects: ['packages/*']` where one of the matched entries is a file (not a directory) whose name fails CONFIG_REGEXP, e.g. a `packages/README.md` or a stray `packages/index.js`. Also triggered by a glob that accidentally includes dotfiles or build artifacts like `packages/vitest.rollup.config.js` only if the segment after `vite`/`vitest` contains chars outside `[\w-]`. Directories ending with `/` are handled separately (resolveDirectoryConfig), so only bare-file matches hit this branch.

Common situations: Pointing `projects` at a flat layout where packages are files rather than folders; renaming a config to something non-conventional (e.g. `vitest.conf.ts`); a glob like `**/vitest.*` that also catches non-config files; monorepo migrations that leave behind a file matching the glob but not the naming convention.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/9a29aa74b5c37612.json. Report an issue: GitHub.