vitest-dev/vitest · error · Error

Tag name " " is invalid. Tag names cannot contain spaces.

Error message

Tag name "${tag.name}" is invalid. Tag names cannot contain spaces.

What it means

Tag names cannot contain whitespace (`/\s/`). Vitest uses tag names in CLI filters and boolean tag expressions where spaces would break tokenisation, so any whitespace is rejected with the offending name in the message.

Solutions

  1. Use a single token: `smoke-test`, `smoke_test`, or `smokeTest`.
  2. Trim and validate before export: `name: rawName.trim()` and assert `!/\s/.test(name)`.
  3. Keep a human-readable `description`/`label` field separate from the machine `name` if your config supports it.

Example fix

// before
export default defineConfig({ test: { tags: [{ name: 'smoke test' }] } })

// after
export default defineConfig({ test: { tags: [{ name: 'smoke-test' }] } })
Defensive patterns

Strategy: validation

Validate before calling

function assertNoSpaces(name: string): void {
  if (/\s/.test(name)) {
    throw new Error(`Tag name "${name}" must not contain whitespace`)
  }
}

const clean = rawTags.map(t => ({ ...t, name: t.name.trim() }))
clean.forEach(t => assertNoSpaces(t.name))

Type guard

function isWhitespaceFreeName(name: string): boolean {
  return typeof name === 'string' && !/\s/.test(name)
}

Prevention

When it happens

Trigger: `{ name: 'smoke test' }`, `{ name: 'flaky\t' }`, `{ name: 'a b' }`, or names with leading/trailing spaces from copy-paste.

Common situations: Pasting human-readable labels as tag names; importing tags from a spreadsheet/CSV that preserved spaces; typos with tabs/newlines.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/ddece76a943e6160. Report an issue: GitHub.

Appendix: source

Thrown at packages/vitest/src/node/config/resolveConfig.ts:296

  }

  resolved.pool ??= 'forks'

  resolved.project = toArray(resolved.project)
  resolved.provide ??= {}

  // shallow copy tags array to avoid mutating user config
  resolved.tags = [...resolved.tags || []]
  const definedTags = new Set<string>()
  resolved.tags.forEach((tag) => {
    if (!tag.name || typeof tag.name !== 'string') {
      throw new Error(`Each tag defined in "test.tags" must have a "name" property, received: ${JSON.stringify(tag)}`)
    }
    if (definedTags.has(tag.name)) {
      throw new Error(`Tag name "${tag.name}" is already defined in "test.tags". Tag names must be unique.`)
    }
    if (/\s/.test(tag.name)) {
      throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot contain spaces.`)
    }
    if (/[!()*|&]/.test(tag.name)) {
      throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot contain "!", "*", "&", "|", "(", or ")".`)
    }
    if (/^\s*(?:and|or|not)\s*$/i.test(tag.name)) {
      throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot be a logical operator like "and", "or", "not".`)
    }
    if (typeof tag.retry === 'object' && typeof tag.retry.condition === 'function') {
      throw new TypeError(`Tag "${tag.name}": retry.condition function cannot be used inside a config file. Use a RegExp pattern instead, or define the function in your test file.`)
    }
    if (tag.priority != null && (typeof tag.priority !== 'number' || tag.priority < 0)) {
      throw new TypeError(`Tag "${tag.name}": priority must be a non-negative number.`)
    }
    definedTags.add(tag.name)
  })

  resolved.name = typeof options.name === 'string'
    ? options.name

View on GitHub (pinned to 1fa9837ec2)