tailwindlabs/tailwindcss · error · Error

The pattern `${pattern}` is not balanced.

Error message

The pattern `${pattern}` is not balanced.

What it means

Thrown by expand() in brace-expansion.ts when a '{' character has no matching closing '}'. The parser walks the pattern tracking nesting depth; if it never returns to depth 0, endIndex stays -1 and the pattern is rejected as unbalanced. This mirrors bash brace-expansion semantics where every opened brace must close.

Source

Thrown at packages/tailwindcss/src/utils/brace-expansion.ts:30

  // Find the matching closing brace
  let depth = 0
  let endIndex = rest.lastIndexOf('}')
  for (let i = 0; i < rest.length; i++) {
    let char = rest[i]
    if (char === '{') {
      depth++
    } else if (char === '}') {
      depth--
      if (depth === 0) {
        endIndex = i
        break
      }
    }
  }

  if (endIndex === -1) {
    throw new Error(`The pattern \`${pattern}\` is not balanced.`)
  }

  let inside = rest.slice(1, endIndex)
  let post = rest.slice(endIndex + 1)
  let parts: string[]

  if (isSequence(inside)) {
    parts = expandSequence(inside)
  } else {
    parts = segment(inside, ',')
  }

  parts = parts.flatMap((part) => expand(part))

  let expandedTail = expand(post)

  for (let tail of expandedTail) {
    for (let part of parts) {

View on GitHub (pinned to 16e94cbf7f)

Solutions

  1. Balance the braces: add the missing '}' (e.g. 'img-{icon' -> 'img-{icon}').
  2. If a literal '{' is intended, escape or avoid the expansion utility for that input.
  3. Validate the pattern before calling expand(): count '{' and '}' and ensure they match.

Example fix

// before — throws
let parts = expand('page-{1..5')

// after
let parts = expand('page-{1..5}')
Defensive patterns

Strategy: validation

Validate before calling

function isBalanced(pattern: string): boolean {
  let depth = 0
  for (const ch of pattern) {
    if (ch === '{') depth++
    else if (ch === '}') depth--
    if (depth < 0) return false
  }
  return depth === 0
}
if (!isBalanced(pattern)) {
  throw new Error(`Unbalanced braces in: ${pattern}`)
}
expand(pattern)

Try / catch

try {
  const parts = expand(pattern)
} catch (e) {
  if (e instanceof Error && /not balanced/.test(e.message)) {
    // fall back to literal pattern
    return [pattern]
  }
  throw e
}

Prevention

When it happens

Trigger: Calling expand() with a pattern containing an unmatched '{', e.g. 'img-{icon' or 'a{b,c'. Internally this is used by Tailwind's arbitrary value and variant parsing, so malformed arbitrary values like 'bg-{red' in class names can surface here.

Common situations: Typos in utility class names with brace syntax. Dynamically generated class strings where a template literal leaves a dangling brace. User input fed into a brace-expansion-based path/glob utility without sanitization.

Related errors


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