vitest-dev/vitest · error · Error
Project name "${name}" from "${entryFile}" is not unique. Th
Error message
Project name "${name}" from "${entryFile}" is not unique. The project is already defined by "${existingFile}". All projects should have unique names. Make sure your configuration is correct. What it means
The detailed duplicate-name error for file-based project resolution. When two resolved entries share a name and there are multiple config files, Vitest reports the declaring file (entryFile) and the file that first claimed the name (existingFile), plus the list of matched config files, so the user can locate both declarations.
Source
Thrown at packages/vitest/src/node/projects/resolveProjects.ts:173
// inline entries carry the configFile they extend, which doesn't say
// where the project is declared, so they are reported without a file
const entryFile = !entry.inline && entry.viteConfig.configFile
? relative(globalConfig.root, entry.viteConfig.configFile)
: ''
const existingFile = !existing.inline && existing.viteConfig.configFile
? relative(globalConfig.root, existing.viteConfig.configFile)
: ''
const filesError = baseEntries.length > 1 && (entryFile || existingFile)
? [
'\n\nYour config matched these files:\n',
baseEntries
.filter(e => !e.inline && e.viteConfig.configFile)
.map(e => ` - ${relative(globalConfig.root, e.viteConfig.configFile as string)}`)
.join('\n'),
'\n\n',
].join('')
: ' '
throw new Error([
`Project name "${name}"`,
entryFile ? ` from "${entryFile}"` : '',
' is not unique.',
existingFile ? ` The project is already defined by "${existingFile}".` : '',
filesError,
'All projects should have unique names. Make sure your configuration is correct.',
].join(''))
}
seenNames.set(name, entry)
}
const seenNamesSet = new Set(seenNames.keys())
// Browser instance expansion (per-entry config injection).
const afterBrowser = expandBrowserInstancesInEntries(globalConfig, baseEntries, seenNamesSet)
// Benchmark expansion (per-entry config injection, runs over post-browser list).
// `--benchmark` makes every project run as a benchmark.
const afterBenchmark = expandBenchmarksInEntries(afterBrowser, seenNamesSet, !!globalConfig.cliOptions.benchmarkOnly)View on GitHub (pinned to 1fa9837ec2)
Solutions
- Rename one of the projects so each config file declares a unique name.
- Read the listed config files in the error to find both declarations.
- If using globs, ensure each matched config sets a distinct, derived name.
- Centralize naming (e.g. derive from directory) to avoid manual collisions.
Example fix
// before - packages/a/vitest.config.ts and packages/b/vitest.config.ts both: test: { name: 'core' }
// after - packages/b
export default defineConfig({ test: { name: 'b-core' } }) Defensive patterns
Strategy: validation
Validate before calling
// Scan config files for duplicate project names before running.
import { globSync } from 'glob'
function findDuplicateProjectNames(configFiles: string[]) {
const seen = new Map<string, string>()
for (const f of configFiles) {
const mod = require(f)
const name = mod?.default?.test?.name
if (!name) continue
if (seen.has(name)) throw new Error(`Duplicate project name "${name}" in ${f} (already in ${seen.get(name)})`)
seen.set(name, f)
}
} Type guard
const allProjectNamesUnique = (entries: { name: string; file?: string }[]): boolean =>
new Set(entries.map(e => e.name)).size === entries.length Prevention
- Derive project names from directory/package name to avoid manual collisions.
- Add a CI check that asserts unique project names across the workspace.
- Use 'vitest list' to audit resolved project names.
When it happens
Trigger: Two non-inline project entries (from different config files) resolve to the same name; baseEntries.length > 1 and at least one has a configFile, producing the file list.
Common situations: A glob/workspace matching multiple config files that each define a project with the same name, copy-pasted project configs, or a monorepo where packages reuse a shared name.
Related errors
- Project name "${name}" is not unique. All projects should ha
- Found a circular "projects" definition: "${file}" -> "${file
- No projects were found in "${relativeFile}". Make sure your
- The file "${relative(parentConfig.root, file)}" must start w
- vitest/browser can be imported only inside the Browser Mode.
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/cd44e9c67b470129.
Report an issue: GitHub.