vitest-dev/vitest · error · Error
Invalid tags expression: missing closing ")" in
Error message
Invalid tags expression: missing closing ")" in "${this.expr}" What it means
Thrown by TokenStream.expect when a closing parenthesis `)` is expected but the stream hit EOF first. It is a specialized, friendlier message for unbalanced parentheses in a `--tags` filter expression, surfaced instead of the generic 'expected ) but got end of expression' message.
Solutions
- Count parentheses and add the missing `)` at the end: `--tags '(foo && bar)'`.
- If nesting, ensure every `(` has a matching `)`.
- Simplify by removing unnecessary grouping parentheses.
Example fix
# before vitest --tags '(smoke || critical' # after vitest --tags '(smoke || critical)'
Defensive patterns
Strategy: validation
Validate before calling
function balancedParens(expr: string): boolean {
let depth = 0
for (const ch of expr) {
if (ch === '(') depth++
else if (ch === ')') depth--
if (depth < 0) return false
}
return depth === 0
}
if (!balancedParens(tagExpr)) throw new Error('Unbalanced parentheses in tags filter') Prevention
- Use an editor that highlights matching parentheses.
- For generated filters, wrap each group and close it on the same edit.
- Prefer flat expressions (a && b || c) when grouping is not required.
When it happens
Trigger: A `--tags` expression with an unclosed `(`: `vitest --tags '(foo'`, `vitest --tags '(foo && bar'`, or `vitest --tags '!(foo || bar'`.
Common situations: Hand-typing a complex filter and missing a closing paren; editing a filter and deleting the trailing `)`; copy-truncation from a terminal.
Related errors
- Invalid tags expression: expected
- Invalid tags expression: unexpected end of expression in
- Invalid tags expression: unexpected
- Invalid tags expression: unexpected
- Unknown value for "test.listTags
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/19df35c33fb4bbe6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/runtime/runner/utils/tags.ts:182
| { type: 'or'; left: ASTNode; right: ASTNode }
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'View on GitHub (pinned to 1fa9837ec2)