tailwindlabs/tailwindcss · error · CssSyntaxError

Missing opening (

Error message

Missing opening (

What it means

Thrown when the parser hits a closing parenthesis `)` but the top of the bracket stack is not `)`. The parser pushes `)` onto `closingBracketStack` for every `(` and pops on every matching `)`; finding a `)` without a matching `(` means parentheses are unbalanced. The error points at the offending `)`.

Source

Thrown at packages/tailwindcss/src/css-parser.ts:533

      // Go up one level in the stack.
      parent = grandParent

      // Reset the state for the next node.
      buffer = ''
      node = null
    }

    // `(`
    else if (currentChar === OPEN_PAREN) {
      closingBracketStack += ')'
      buffer += '('
    }

    // `)`
    else if (currentChar === CLOSE_PAREN) {
      if (closingBracketStack[closingBracketStack.length - 1] !== ')') {
        throw new CssSyntaxError('Missing opening (', source ? [source, i, i] : null)
      }

      closingBracketStack = closingBracketStack.slice(0, -1)
      buffer += ')'
    }

    // Any other character is part of the current node.
    else {
      // Skip whitespace at the start of a new node.
      if (
        buffer.length === 0 &&
        (currentChar === SPACE || currentChar === LINE_BREAK || currentChar === TAB)
      ) {
        continue
      }

      if (buffer === '') bufferStart = i

View on GitHub (pinned to 16e94cbf7f)

Solutions

  1. Balance parentheses in the offending expression — remove the surplus `)`.
  2. Use an editor with paren-matching to find the unmatched closer.
  3. For complex `calc()`/`var()` chains, format and re-read the expression.
  4. If the CSS is generated, fix the template that emits the extra paren.

Example fix

/* before */
.x { width: calc(100% - 10px)); }
/* after */
.x { width: calc(100% - 10px); }
Defensive patterns

Strategy: validation

Validate before calling

function parensBalanced(css: string): boolean {
  let depth = 0;
  for (const ch of css) {
    if (ch === '(') depth++;
    else if (ch === ')') depth--;
    if (depth < 0) return false;
  }
  return depth === 0;
}
if (!parensBalanced(input)) throw new Error('Unbalanced parentheses');

Try / catch

try {
  const ast = CSS.parse(input);
} catch (e) {
  if (e instanceof CssSyntaxError && e.message === 'Missing opening (') {
    // use source coords to find the extra )
  } else throw e;
}

Prevention

When it happens

Trigger: An extra `)` in a value or selector, e.g. `.x { width: calc(100% - 10px)); }`, `@media (min-width: 100px)) { ... }`, or a function call closed twice. Also triggered by a `)` appearing when the stack top is `}` (i.e. inside an unclosed curly).

Common situations: Typing an extra `)`; broken `calc()` / `var()` / `color-mix()` expressions; generated CSS that double-closes functions; copy-paste errors.

Related errors


AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12). Data as JSON: /api/errors/7a9356e11cbec38a. Report an issue: GitHub.