microsoft/playwright · error · Error

Invalid glob pattern ${JSON.stringify(glob)}: nested '{' is

Error message

Invalid glob pattern ${JSON.stringify(glob)}: nested '{' is not supported

What it means

Thrown by globToRegexPattern when a `{` is encountered while already inside a brace group (inGroup is true). The glob-to-regex converter supports single-level alternation `{a,b}` but does not support nesting, so a second `{` before the group closes is rejected.

Source

Thrown at packages/isomorphic/urlMatch.ts:68

        if (charAfter === '/') {
          if (charBefore === '/')
            tokens.push('((.+/)|)');
          else
            tokens.push('(.*/)');
          ++i;
        } else {
          tokens.push('(.*)');
        }
      } else {
        tokens.push('([^/]*)');
      }
      continue;
    }

    switch (c) {
      case '{':
        if (inGroup)
          throw new Error(`Invalid glob pattern ${JSON.stringify(glob)}: nested '{' is not supported`);
        inGroup = true;
        tokens.push('(');
        break;
      case '}':
        if (!inGroup)
          throw new Error(`Invalid glob pattern ${JSON.stringify(glob)}: unmatched '}'`);
        inGroup = false;
        tokens.push(')');
        break;
      case ',':
        if (inGroup) {
          tokens.push('|');
          break;
        }
        tokens.push('\\' + c);
        break;
      default:
        tokens.push(escapedChars.has(c) ? '\\' + c : c);

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Flatten the alternation into a single level: `{a,b,c}` instead of `{a,{b,c}}`.
  2. Split into multiple route handlers if true nesting semantics are required.
  3. Switch to a RegExp match for complex alternation logic.

Example fix

// before
page.route('**/{api,{v1,v2}}/*', handler);  // nested brace

// after
page.route('**/{api,v1,v2}/*', handler);
Defensive patterns

Strategy: validation

Validate before calling

function assertNoNestedBraces(glob: string) {
  let depth = 0;
  for (const c of glob) {
    if (c === '{') depth++;
    if (c === '}') depth--;
    if (depth > 1) throw new Error(`Glob has nested braces: ${glob}`);
    if (depth < 0) throw new Error(`Glob has unmatched }: ${glob}`);
  }
  if (depth !== 0) throw new Error(`Glob has unmatched {: ${glob}`);
}

Type guard

function isFlatGlob(glob: string): boolean {
  let depth = 0;
  for (const c of glob) {
    if (c === '{') depth++;
    else if (c === '}') depth--;
    if (depth > 1) return false;
  }
  return depth === 0;
}

Try / catch

try {
  page.route(glob, handler);
} catch (e) {
  if (/nested '\{' is not supported/.test(e.message)) {
    glob = flattenAlternation(glob); // user-supplied flattener
    page.route(glob, handler);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a glob with nested alternation to urlMatches/route, e.g. `'{a,{b,c}}'`, `page.route('**/{foo,{bar,baz}}', ...)`, or `page.goto` baseURL glob with `{...{...}...}`. Triggered in the `case '{'` branch when inGroup is already true.

Common situations: Copying a shell/extglob pattern into a Playwright URL glob; attempting nested OR groups; building globs from templated fragments that double up braces.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/51c962e2fe7eb88d. Report an issue: GitHub.