vitest-dev/vitest · error · Error
Invalid tags expression: unexpected "${formatToken(token)}"
Error message
Invalid tags expression: unexpected "${formatToken(token)}" in "${this.expr}" What it means
Thrown by TokenStream.unexpectedToken when the parser needs a primary operand but finds a non-EOF token that cannot start one (a ')', '&&', '||', or a stray operator in the wrong position). It is the general 'I did not expect this here' parser error.
Source
Thrown at packages/vitest/src/runtime/runner/utils/tags.ts:194
}
expect(type: Token['type']): Token {
const token = this.next()
if (token.type !== type) {
if (type === 'RPAREN' && token.type === 'EOF') {
throw new Error(`Invalid tags expression: missing closing ")" in "${this.expr}"`)
}
throw new Error(`Invalid tags expression: expected "${formatTokenType(type)}" but got "${formatToken(token)}" in "${this.expr}"`)
}
return token
}
unexpectedToken(): never {
const token = this.peek()
if (token.type === 'EOF') {
throw new Error(`Invalid tags expression: unexpected end of expression in "${this.expr}"`)
}
throw new Error(`Invalid tags expression: unexpected "${formatToken(token)}" in "${this.expr}"`)
}
}
function formatTokenType(type: Token['type']): string {
switch (type) {
case 'TAG': return 'tag'
case 'AND': return 'and'
case 'OR': return 'or'
case 'NOT': return 'not'
case 'LPAREN': return '('
case 'RPAREN': return ')'
case 'EOF': return 'end of expression'
}
}
function parseOrExpression(stream: TokenStream, availableTags: TestTagDefinition[]): ASTNode {
let left = parseAndExpression(stream, availableTags)
View on GitHub (pinned to d568f8ce37)
Solutions
- Make sure the expression starts with a tag, '!', or '('.
- Never place two operators adjacent to each other.
- Ensure every '(' contains at least one complete sub-expression.
- Rewrite the filter as a clean boolean tree of tags joined by && / || / !.
Example fix
// before vitest --tag '&& unit' vitest --tag '()' // after vitest --tag 'unit' vitest --tag '(unit && smoke)'
Defensive patterns
Strategy: validation
Validate before calling
// Reject expressions that start with a binary operator or contain empty groups
function isWellFormedStart(expr: string): boolean {
const t = expr.trim()
if (/^(?:&&|\|\|)/.test(t)) return false
if (/\(\s*\)/.test(t)) return false
return true
} Prevention
- Start every expression with a tag, '!', or '('.
- Never place two operators adjacent to each other.
- Never use empty parentheses ().
When it happens
Trigger: `--tag '&& unit'` (expression starts with AND). `--tag 'unit (smoke)'` (group right after a tag with no operator). `--tag '()'` (empty group). `--tag 'unit && && smoke'` (two operators in a row).
Common situations: Misunderstanding that an expression must start with a tag, '!', or '('. Joining operators incorrectly. Empty parentheses.
Related errors
- Invalid tags expression: unexpected "${formatToken(stream.pe
- Invalid tags expression: missing closing ")" in "${this.expr
- Invalid tags expression: expected "${formatTokenType(type)}"
- Invalid tags expression: unexpected end of expression in "${
- failed to parse ${options.id}
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/3c8a25a7767e4162.json.
Report an issue: GitHub.