vitest-dev/vitest · error · Error
Tag name "${tag.name}" is invalid. Tag names cannot be a log
Error message
Tag name "${tag.name}" is invalid. Tag names cannot be a logical operator like "and", "or", "not". What it means
Thrown during tag validation when a tag name is (case-insensitively) exactly `and`, `or`, or `not` (regex /^\s*(?:and|or|not)\s*$/i). These are the reserved logical operator keywords of the tag-filter expression grammar; using one as a tag name would make every filter expression containing it ambiguous, so they are forbidden even though they contain no forbidden characters.
Source
Thrown at packages/vitest/src/node/config/resolveConfig.ts:274
// 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
: (options.name?.label || '')
resolved.color = typeof options.name !== 'string' ? options.name?.color : undefined
if (resolved.environment === 'browser') {
throw new Error(`Looks like you set "test.environment" to "browser". To enable Browser Mode, use "test.browser.enabled" instead.`)View on GitHub (pinned to d568f8ce37)
Solutions
- Rename the tag to a non-keyword: 'and-condition', 'logical-or', 'negated', etc.
- Reserve the keywords and validate generated names against the same regex before assigning.
Example fix
// before
export default defineConfig({ test: { tags: [{ name: 'or' }] } })
// after
export default defineConfig({ test: { tags: [{ name: 'or-condition' }] } }) Defensive patterns
Strategy: validation
Validate before calling
if (/^\s*(?:and|or|not)\s*$/i.test(name)) {
throw new Error(`tag name is a reserved operator: ${name}`)
} Type guard
function isValidTagName(name: string): boolean {
return name.length > 0 && !/\s/.test(name) && !/[!()*|&]/.test(name)
&& !/^\s*(?:and|or|not)\s*$/i.test(name)
} Prevention
- Avoid the reserved keywords and/or/not as tag names (case-insensitive).
- Reserve keywords in any tag-name generator.
- Validate names with isValidTagName before assigning.
When it happens
Trigger: Defining `test.tags: [{ name: 'and' }]`, `[{ name: 'OR' }]`, or `[{ name: ' not ' }]`. The keyword regex matches case-insensitively with optional surrounding whitespace.
Common situations: Tag names that mirror domain vocabulary ('and', 'or', 'not' as boolean-style labels); names auto-generated from boolean flags; localized labels colliding with English keywords.
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/a92daa33e369dfac.json.
Report an issue: GitHub.