vitest-dev/vitest · error · Error

Project name "${name}" is not unique. All projects should ha

Error message

Project name "${name}" is not unique. All projects should have unique names. Make sure your configuration is correct.

What it means

Thrown by the runtime inject path (resolveProjects.ts:145-148) when resolveProjectEntries is called with existingNames (the set of already-active project names) and a newly injected project's name collides with one of them. This is the shorter message used when names clash against the live workspace rather than within a single resolution batch.

Source

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

        ...(globalConfig._containerConfigFiles || []),
        ...containerConfigFiles,
      ]
    }
  }
  else {
    baseEntries = [{ viteConfig: globalViteConfig, projectConfig: globalConfig }]
  }

  // Ensure project names are unique across declared projects (and any
  // already-existing projects passed via `existingNames`, which the inject
  // path uses to forbid clashes with the active workspace). Include config
  // file paths in the error when available (matches the old workspace-mode
  // duplicate-name diagnostic).
  const seenNames = new Map<string, ResolvedProjectEntry>()
  for (const entry of baseEntries) {
    const name = entry.projectConfig.name
    if (existingNames?.has(name)) {
      throw new Error(
        `Project name "${name}" is not unique. All projects should have unique names. Make sure your configuration is correct.`,
      )
    }
    const existing = seenNames.get(name)
    if (existing) {
      // 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)

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Before injecting, check vitest.projects.map(p => p.name) and pick a unique name.
  2. Set an explicit test.name on the injected config to avoid auto-resolution collisions.
  3. Close or remove the existing project before re-injecting under the same name.
  4. If the duplicate is unintentional, audit your workspace/projects array for two entries resolving to the same name.

Example fix

// before
await vitest.injectTestProjects([{ test: { name: 'unit', environment: 'node' } }]) // 'unit' already exists

// after
const used = new Set(vitest.projects.map(p => p.name))
await vitest.injectTestProjects([{ test: { name: used.has('unit') ? 'unit-2' : 'unit', environment: 'node' } }])
Defensive patterns

Strategy: validation

Validate before calling

const used = new Set(vitest.projects.map(p => p.name))
const candidate = newProjectName
if (used.has(candidate)) throw new Error(`Name '${candidate}' already in active workspace`)
await vitest.injectTestProjects([definition])

Type guard

function isUniqueName(name: string, existing: Set<string>): boolean {
  return !existing.has(name)
}

Prevention

When it happens

Trigger: Calling vitest.injectTestProjects (resolveAndAttachProjects at resolveProjects.ts:1235) with a definition whose test.name matches an already-running project; injecting a project whose auto-resolved name (package.json name or directory basename) matches an existing one.

Common situations: A plugin or watch-mode reload injects a project whose name duplicates the original; dynamically adding a project at runtime without checking the active project list; two workspace entries that resolve to the same package.json name.

Related errors


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