vitest-dev/vitest · error · Error

Invalid tags expression: unexpected

Error message

Invalid tags expression: unexpected "${formatToken(token)}" in "${this.expr}"

What it means

Thrown by TokenStream.unexpectedToken when the parser is at a primary-expression position and the current token is neither a tag nor a left-paren (and is not EOF, which is handled separately by error 345). The message names the offending token so the user can locate it.

Solutions

  1. Start the expression (and every sub-expression) with a tag name or `(`: `--tags 'foo'` or `--tags '(foo || bar)'`.
  2. Remove the leading/stray operator identified by 'unexpected' in the message.
  3. When building filters in code, join non-empty fragments only: `parts.filter(Boolean).join(' && ')`.

Example fix

# before
vitest --tags '&& smoke'

# after
vitest --tags 'smoke'
Defensive patterns

Strategy: validation

Validate before calling

function startsWithTagOrParen(expr: string): boolean {
  return /^\s*(?:!?[\w*-]+|\()/.test(expr)
}

Prevention

When it happens

Trigger: A `--tags` filter starting with a binary operator (`vitest --tags '&& foo'`), a `)` with no matching `(` (`vitest --tags 'foo)'` — though this often hits 342), a leading operator inside a group (`--tags '(&& foo)'`), or any token that cannot begin a primary expression.

Common situations: Pasting an expression and losing its first token; building filters dynamically and joining with a leading `&&`/`||`; stray punctuation; mismatched parentheses producing a `)` where a value is expected.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/3c8a25a7767e4162. Report an issue: GitHub.

Appendix: 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 1fa9837ec2)