vitest-dev/vitest · error · Error
Root path does not exist or is not a directory
Error message
Root path does not exist or is not a directory: ${resolved.root} What it means
During config resolution Vitest `statSync`s the resolved `root` with `throwIfNoEntry: false` and requires the result to be a directory. If the path is missing, is a file, or is any non-directory entry, it throws with the resolved path so the user can see exactly what was checked.
Solutions
- Verify the path exists and is a directory: `ls -la <root>`.
- Use an absolute path or one resolvable from cwd; print `path.resolve(process.cwd(), root)` to confirm.
- If pointing at a monorepo package, set `root` to that package folder, not a config file.
- Create the missing directory or fix the typo in `vitest.config.ts` / `--root`.
Example fix
// before
export default defineConfig({ test: { root: './config' } }) // './config' is a file
// after
export default defineConfig({ test: { root: './tests' } }) // directory exists Defensive patterns
Strategy: validation
Validate before calling
import { statSync } from 'node:fs'
import { resolve } from 'node:path'
function assertRootValid(rawRoot: string): string {
const root = resolve(process.cwd(), rawRoot)
const stats = statSync(root, { throwIfNoEntry: false })
if (!stats?.isDirectory()) {
throw new Error(`Root is not a directory: ${root}`)
}
return root
}
export default defineConfig({ test: { root: assertRootValid(configRoot) } }) Prevention
- Print `path.resolve(cwd, root)` during config debugging to confirm what Vitest will check.
- Use absolute roots in CI to avoid cwd surprises.
- Point `root` at a directory, never at a config or source file.
When it happens
Trigger: Setting `root: './nonexistent'`, `root: './vitest.config.ts'` (a file, not a dir), `root: ''` (resolves to cwd that may be invalid in some sandboxes), or a relative root that resolves against an unexpected cwd. Also triggered by `--root` CLI flag pointing outside the project.
Common situations: Monorepo where `root` should be a package path but is set to the workspace root that lacks the expected structure; typos in config; running Vitest from a different cwd than expected; CI checkout missing a directory.
Related errors
- Access denied to " ". See Vite config documentation for…
- Each tag defined in "test.tags" must have a "name"…
- Projects definition references a non-existing file or a…
- You cannot set "coverage.reportsDirectory" as
- Access denied to " ". See Vite config documentation for…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/f766d446df79aaac.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/node/config/resolveConfig.ts:250
viteConfig.test as UserConfig | undefined,
)
const resolved = deepMerge({}, configDefaults, options) as ResolvedConfig
resolved.root = viteConfig.root
resolved.providedOptions = providedOptions
// These options are resolved once for the whole run using the root config.
// Coverage is shared by reference: each project's setup/test/config files are
// appended to the same exclude list below, keeping them out of the report.
if (globalConfig) {
resolved.coverage = globalConfig.coverage
resolved.attachmentsDir = globalConfig.attachmentsDir
resolved.mergeReportsLabel = globalConfig.mergeReportsLabel
}
const rootStats = statSync(resolved.root, { throwIfNoEntry: false })
if (!rootStats?.isDirectory()) {
throw new Error(`Root path does not exist or is not a directory: ${resolved.root}`)
}
resolved.mode ??= viteConfig.mode ?? 'test'
if (resolved.retry && typeof resolved.retry === 'object' && typeof resolved.retry.condition === 'function') {
logger.warn(
c.yellow('Warning: retry.condition function cannot be used inside a config file. '
+ 'Use a RegExp pattern instead, or define the function in your test file.'),
)
resolved.retry = {
...resolved.retry,
condition: undefined,
}
}
if (options.pool && typeof options.pool !== 'string') {
resolved.pool = options.pool.nameView on GitHub (pinned to 1fa9837ec2)