vitest-dev/vitest · error · Error
Each tag defined in "test.tags" must have a "name"…
Error message
Each tag defined in "test.tags" must have a "name" property, received: ${JSON.stringify(tag)} What it means
Every entry in `test.tags` must be an object with a string `name`. During resolution Vitest iterates `resolved.tags` and rejects the first entry whose `name` is falsy or non-string, including the JSON of the offending tag so the user can see exactly which entry is malformed.
Solutions
- Wrap each tag as `{ name: 'smoke' }`.
- Validate tags before exporting config: `tags.every(t => t && typeof t.name === 'string' && t.name)`.
- If you want a shorthand, map strings to objects in the config: `tags: ['smoke','flaky'].map(name => ({ name }))`.
Example fix
// before
export default defineConfig({ test: { tags: ['smoke', { label: 'flaky' }] } })
// after
export default defineConfig({ test: { tags: [{ name: 'smoke' }, { name: 'flaky' }] } }) Defensive patterns
Strategy: validation
Validate before calling
type Tag = { name: string; [k: string]: unknown }
function normalizeTags(input: unknown[]): Tag[] {
return input.map((t, i) => {
const tag = typeof t === 'string' ? { name: t } : (t as Tag)
if (!tag || typeof tag.name !== 'string' || !tag.name) {
throw new Error(`tags[${i}] must have a non-empty string "name"; got ${JSON.stringify(t)}`)
}
return tag
})
}
export default defineConfig({ test: { tags: normalizeTags(rawTags) } }) Type guard
function isTag(v: unknown): v is { name: string } {
return typeof v === 'object' && v !== null
&& typeof (v as any).name === 'string' && (v as any).name.length > 0
} Prevention
- Always use the object form `{ name }` for tags, never bare strings.
- Validate the tags array in a small helper before exporting config.
- Document the tag schema for contributors adding new tags.
When it happens
Trigger: Passing a plain string (`tags: ['smoke']`) instead of objects; an entry like `{ label: 'smoke' }` missing `name`; `tags: [{ name: '' }]` or `tags: [{ name: null }]`; an undefined element slipped in via spread.
Common situations: Treating `tags` like Mocha/Pytest string tags; copy-pasting from docs of a different framework; building tags programmatically and forgetting the `name` field.
Related errors
- Tag name " " is already defined in "test.tags". Tag names…
- Tag name " " is invalid. Tag names cannot contain spaces.
- Tag name " " is invalid. Tag names cannot be a logical…
- Tag name " " is invalid. Tag names cannot contain "!", "*"…
- Tag " ": priority must be a non-negative number.
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/512a729cfec9e8db.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/node/config/resolveConfig.ts:290
if ('poolOptions' in resolved) {
logger.deprecate('`test.poolOptions` was removed in Vitest 4. All previous `poolOptions` are now top-level options. Please, refer to the migration guide: https://v4.vitest.dev/guide/migration#pool-rework')
}
if ('workspace' in resolved) {
throw new Error('The `test.workspace` option was removed in Vitest 4. Please, migrate to `test.projects` instead. See https://vitest.dev/guide/projects for examples.')
}
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.`)View on GitHub (pinned to 1fa9837ec2)