vitest-dev/vitest · error · Error
Invalid tags expression: expected "${formatTokenType(type)}"
Error message
Invalid tags expression: expected "${formatTokenType(type)}" but got "${formatToken(token)}" in "${this.expr}" What it means
Thrown by TokenStream.expect when a specific token type was required but a different one appeared. Currently the only path that reaches a non-RPAREN expect is expect('RPAREN') hitting a non-EOF token (line 184 fires for that case), so in practice this message means: expected a ')' but got some other token (a tag, '&&', etc.) before end of input.
Source
Thrown at packages/vitest/src/runtime/runner/utils/tags.ts:184
class TokenStream {
private pos = 0
constructor(private tokens: Token[], public expr: string) {}
peek(): Token {
return this.tokens[this.pos]
}
next(): Token {
return this.tokens[this.pos++]
}
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'View on GitHub (pinned to d568f8ce37)
Solutions
- Insert the missing operator between tokens inside the group: `(a && b)`.
- Remove the unexpected token so the inner expression is a single complete or/and/not tree.
- Validate the expression is a single balanced boolean tree of tags and operators.
Example fix
// before vitest --tag '(unit smoke)' // after vitest --tag '(unit || smoke)'
Defensive patterns
Strategy: validation
Validate before calling
// Reject expressions where a TAG is immediately followed by another TAG or by ')'
function hasAdjacentOperands(expr: string): boolean {
return /(\b\w+\b)\s+(\b\w+\b)/.test(expr) // crude: flag for manual review
} Prevention
- Place an operator between every pair of tags inside a group.
- Do not put operators directly before a closing paren.
- Lint filter expressions in a preflight step.
When it happens
Trigger: A tag filter like `--tag '(unit smoke)'` where the inner expression `unit smoke` has two tags with no operator; after parsing 'unit' the and/or loops stop at the bare 'smoke' token, then expect(RPAREN) finds the 'smoke' TAG token instead of ')'.
Common situations: Putting two tags inside parentheses without an operator: `(a b)`. Adding an operator before the closing paren like `(a && )`.
Related errors
- Invalid tags expression: unexpected "${formatToken(stream.pe
- Invalid tags expression: missing closing ")" in "${this.expr
- Invalid tags expression: unexpected end of expression in "${
- Invalid tags expression: unexpected "${formatToken(token)}"
- failed to parse ${options.id}
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/cc39c0d2aee95435.json.
Report an issue: GitHub.