{"record":{"id":"0daa5ae350a435ba","repo":"vitest-dev/vitest","slug":"projects-definition-references-a-non-existing-file","errorCode":null,"errorMessage":"Projects definition references a non-existing file or a directory: ${file}","messagePattern":"Projects definition references a non-existing file or a directory: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/projects/resolveProjects.ts","lineNumber":1182,"sourceCode":"  // custom config files that were specified directly or resolved from a directory\n  const projectsConfigFiles: string[] = []\n\n  // custom glob matches that should be resolved as directories or config files\n  const projectsGlobMatches: string[] = []\n\n  // directories that don't have a config file inside, but should be treated as projects\n  const nonConfigProjectDirectories: string[] = []\n\n  for (const definition of projectsDefinition) {\n    if (typeof definition === 'string') {\n      const stringOption = definition.replace('<rootDir>', parentConfig.root)\n      // if the string doesn't contain a glob, we can resolve it directly\n      // ['./vitest.config.js']\n      if (!isDynamicPattern(stringOption)) {\n        const file = resolve(parentConfig.root, stringOption)\n\n        if (!existsSync(file)) {\n          throw new Error(`Projects definition references a non-existing file or a directory: ${file}`)\n        }\n\n        const stats = statSync(file)\n        // user can specify a config file directly\n        if (stats.isFile()) {\n          const name = basename(file)\n          if (!CONFIG_REGEXP.test(name)) {\n            throw new Error(\n              `The file \"${relative(parentConfig.root, file)}\" must start with \"vitest.config\"/\"vite.config\" `\n              + `or match the pattern \"(vitest|vite).*.config.*\" to be a valid project config.`,\n            )\n          }\n\n          projectsConfigFiles.push(file)\n        }\n        // user can specify a directory that should be used as a project\n        else if (stats.isDirectory()) {\n          const configFile = resolveDirectoryConfig(file)","sourceCodeStart":1164,"sourceCodeEnd":1200,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/node/projects/resolveProjects.ts#L1164-L1200","documentation":"When `projects` contains a literal string (not a glob), Vitest resolves it relative to the parent config's `root` and verifies the path exists immediately. A missing path is treated as a configuration error rather than silently skipped, so a typo doesn't quietly drop a project.","triggerScenarios":"A `projects` array entry that is a plain string (not a dynamic/glob pattern per `isDynamicPattern`) whose `resolve(root, entry)` fails `existsSync`.","commonSituations":"Typo in the path; referencing a config file that was renamed or moved; sparse CI checkout missing a sub-project; case-sensitivity mismatch between macOS and Linux.","solutions":["Correct the path so it points to an existing file or directory.","If the path is intentionally optional, use a glob (e.g. `./configs/vitest.*.ts`) which is resolved lazily and tolerates zero matches.","Verify `root` is what you expect (path is resolved against `parentConfig.root`)."],"exampleFix":"// before\nexport default defineConfig({ test: { projects: ['./packages/ap/vitest.conf.ts'] } })\n\n// after (fixed typo)\nexport default defineConfig({ test: { projects: ['./packages/app/vitest.config.ts'] } })\n\n// after (optional, glob-based)\nexport default defineConfig({ test: { projects: ['./packages/*/vitest.config.ts'] } })","handlingStrategy":"validation","validationCode":"import { existsSync } from 'node:fs'\nimport { resolve, isAbsolute } from 'node:path'\nimport pm from 'picomatch'\n\nfunction assertProjectsPathsExist(root: string, projects: unknown[]) {\n  for (const def of projects) {\n    if (typeof def !== 'string') continue\n    if (pm.isMatch(def, '**') || /[*/?]/.test(def)) continue // glob, resolved lazily\n    const file = resolve(root, def.replace('<rootDir>', root))\n    if (!existsSync(file)) {\n      throw new Error(`projects entry '${def}' does not exist: ${file}`)\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use globs for optional project paths so a missing match is tolerated.","Pin literal paths only to files guaranteed present (e.g. committed sub-configs)."],"tags":["config","projects","filesystem"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}