vitest-dev/vitest · error · Error

Projects definition references a non-existing file or a dire

Error message

Projects definition references a non-existing file or a directory: ${file}

What it means

In resolveTestProjectConfigs (resolveProjects.ts:982-986), a string entry in the projects array that isn't a glob is resolved to an absolute path and checked with existsSync. If the file or directory doesn't exist on disk, Vitest throws naming the resolved path. This catches typos and stale references before config resolution.

Source

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

  // custom config files that were specified directly or resolved from a directory
  const projectsConfigFiles: string[] = []

  // custom glob matches that should be resolved as directories or config files
  const projectsGlobMatches: string[] = []

  // directories that don't have a config file inside, but should be treated as projects
  const nonConfigProjectDirectories: string[] = []

  for (const definition of projectsDefinition) {
    if (typeof definition === 'string') {
      const stringOption = definition.replace('<rootDir>', parentConfig.root)
      // if the string doesn't contain a glob, we can resolve it directly
      // ['./vitest.config.js']
      if (!isDynamicPattern(stringOption)) {
        const file = resolve(parentConfig.root, stringOption)

        if (!existsSync(file)) {
          throw new Error(`Projects definition references a non-existing file or a directory: ${file}`)
        }

        const stats = statSync(file)
        // user can specify a config file directly
        if (stats.isFile()) {
          const name = basename(file)
          if (!CONFIG_REGEXP.test(name)) {
            throw new Error(
              `The file "${relative(parentConfig.root, file)}" must start with "vitest.config"/"vite.config" `
              + `or match the pattern "(vitest|vite).*.config.*" to be a valid project config.`,
            )
          }

          projectsConfigFiles.push(file)
        }
        // user can specify a directory that should be used as a project
        else if (stats.isDirectory()) {
          const configFile = resolveDirectoryConfig(file)

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Verify the path exists: run ls on the resolved absolute path printed in the error.
  2. Fix the typo or update the entry to the new location.
  3. If the project was removed intentionally, delete the entry from the projects array.
  4. Use a glob (e.g. 'packages/*/vitest.config.ts') instead of a hardcoded path to be resilient to layout changes.

Example fix

// before
export default defineConfig({ test: { projects: ['./vitest.unit.config.ts'] } }) // missing

// after
export default defineConfig({ test: { projects: ['./vitest.unit.config.mts'] } }) // correct extension
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'node:fs'
import { resolve } from 'node:path'
for (const def of definitions) {
  if (typeof def === 'string' && !def.includes('*')) {
    const abs = resolve(root, def)
    if (!existsSync(abs)) throw new Error(`projects entry '${def}' resolves to non-existing path: ${abs}`)
  }
}

Type guard

function pathExists(p: string): boolean { return existsSync(p) }

Prevention

When it happens

Trigger: projects: ['./vitest.unit.config.ts'] where the file doesn't exist; projects: ['packages/foo'] after packages/foo was renamed/deleted; a relative path that resolves against the wrong root; using <rootDir> substitution that yields a non-existent path.

Common situations: Renaming or deleting a config file/directory without updating the workspace entry; monorepo restructure; typo in the path; CI checkout missing a workspace package.

Related errors


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