{"id":"a92daa33e369dfac","repo":"vitest-dev/vitest","slug":"tag-name-tag-name-is-invalid-tag-names-canno-a92daa","errorCode":null,"errorMessage":"Tag name \"${tag.name}\" is invalid. Tag names cannot be a logical operator like \"and\", \"or\", \"not\".","messagePattern":"Tag name \"(.+?)\" is invalid\\. Tag names cannot be a logical operator like \"and\", \"or\", \"not\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/config/resolveConfig.ts","lineNumber":274,"sourceCode":"\n  // shallow copy tags array to avoid mutating user config\n  resolved.tags = [...resolved.tags || []]\n  const definedTags = new Set<string>()\n  resolved.tags.forEach((tag) => {\n    if (!tag.name || typeof tag.name !== 'string') {\n      throw new Error(`Each tag defined in \"test.tags\" must have a \"name\" property, received: ${JSON.stringify(tag)}`)\n    }\n    if (definedTags.has(tag.name)) {\n      throw new Error(`Tag name \"${tag.name}\" is already defined in \"test.tags\". Tag names must be unique.`)\n    }\n    if (/\\s/.test(tag.name)) {\n      throw new Error(`Tag name \"${tag.name}\" is invalid. Tag names cannot contain spaces.`)\n    }\n    if (/[!()*|&]/.test(tag.name)) {\n      throw new Error(`Tag name \"${tag.name}\" is invalid. Tag names cannot contain \"!\", \"*\", \"&\", \"|\", \"(\", or \")\".`)\n    }\n    if (/^\\s*(?:and|or|not)\\s*$/i.test(tag.name)) {\n      throw new Error(`Tag name \"${tag.name}\" is invalid. Tag names cannot be a logical operator like \"and\", \"or\", \"not\".`)\n    }\n    if (typeof tag.retry === 'object' && typeof tag.retry.condition === 'function') {\n      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.`)\n    }\n    if (tag.priority != null && (typeof tag.priority !== 'number' || tag.priority < 0)) {\n      throw new TypeError(`Tag \"${tag.name}\": priority must be a non-negative number.`)\n    }\n    definedTags.add(tag.name)\n  })\n\n  resolved.name = typeof options.name === 'string'\n    ? options.name\n    : (options.name?.label || '')\n\n  resolved.color = typeof options.name !== 'string' ? options.name?.color : undefined\n\n  if (resolved.environment === 'browser') {\n    throw new Error(`Looks like you set \"test.environment\" to \"browser\". To enable Browser Mode, use \"test.browser.enabled\" instead.`)","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/node/config/resolveConfig.ts#L256-L292","documentation":"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.","triggerScenarios":"Defining `test.tags: [{ name: 'and' }]`, `[{ name: 'OR' }]`, or `[{ name: ' not ' }]`. The keyword regex matches case-insensitively with optional surrounding whitespace.","commonSituations":"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.","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."],"exampleFix":"// before\nexport default defineConfig({ test: { tags: [{ name: 'or' }] } })\n// after\nexport default defineConfig({ test: { tags: [{ name: 'or-condition' }] } })","handlingStrategy":"validation","validationCode":"if (/^\\s*(?:and|or|not)\\s*$/i.test(name)) {\n  throw new Error(`tag name is a reserved operator: ${name}`)\n}","typeGuard":"function isValidTagName(name: string): boolean {\n  return name.length > 0 && !/\\s/.test(name) && !/[!()*|&]/.test(name)\n    && !/^\\s*(?:and|or|not)\\s*$/i.test(name)\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":[],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}