microsoft/playwright · error · Error
Invalid glob pattern ${JSON.stringify(glob)}: unmatched '{'
Error message
Invalid glob pattern ${JSON.stringify(glob)}: unmatched '{' What it means
Thrown by globToRegexPattern after processing all characters when inGroup is still true, i.e. a `{` was opened but never closed with `}`. The incomplete alternation cannot produce a valid regex, so the converter rejects it.
Source
Thrown at packages/isomorphic/urlMatch.ts:90
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);
}
}
if (inGroup)
throw new Error(`Invalid glob pattern ${JSON.stringify(glob)}: unmatched '{'`);
tokens.push('$');
return tokens.join('');
}
function isRegExp(obj: any): obj is RegExp {
return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';
}
export type URLMatch = string | RegExp | ((url: URL) => boolean) | URLPattern;
// URLPattern is not in @types/node@18, so we polyfill it ourselves
export type URLPattern = {
test(input: string | URL): boolean;
hash: string;
hostname: string;
password: string;
pathname: string;
port: string;
protocol: string;View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Add the missing closing `}` to complete the alternation.
- Escape the `{` as `\{` if it is meant literally.
- Validate brace balance in dynamic glob strings before use.
Example fix
// before
const env = 'staging';
page.route(`**/{${env}`, handler); // missing }
// after
page.route(`**/{${env}}`, handler); Defensive patterns
Strategy: validation
Validate before calling
function assertGlobTerminated(glob: string) {
const opens = (glob.match(/{/g) ?? []).length;
const closes = (glob.match(/}/g) ?? []).length;
if (opens !== closes) throw new Error(`Glob braces unbalanced (${opens}/{ vs ${closes}/}): ${glob}`);
} Type guard
function isTerminatedGlob(glob: string): boolean {
return (glob.match(/{/g) ?? []).length === (glob.match(/}/g) ?? []).length;
} Try / catch
try {
page.route(glob, handler);
} catch (e) {
if (/unmatched '\{'/.test(e.message)) {
glob += '}'; // append missing closer when safe to infer
page.route(glob, handler);
} else throw e;
} Prevention
- When interpolating a list into `{...}`, ensure the closing brace is always emitted.
- Validate brace balance in glob-building helpers.
- Prefer a RegExp over complex globs.
When it happens
Trigger: Passing a glob with an unterminated brace group, e.g. `'{foo,bar'`, `page.route('**/{api', ...)`, or any glob where `{` has no matching `}`. Triggered by the `if (inGroup)` check after the loop.
Common situations: Truncated glob string; template interpolation that omits the closing brace; partial paste of an alternation pattern; off-by-one in dynamic glob construction.
Related errors
- Invalid glob pattern ${JSON.stringify(glob)}: nested '{' is
- Invalid glob pattern ${JSON.stringify(glob)}: unmatched '}'
- Error while parsing selector `${selector}` - selector cannot
- url parameter should be string, RegExp, URLPattern or functi
- Unsupported token "${unsupportedToken.toSource()}" while par
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/a2054b9a9fbf5f35.
Report an issue: GitHub.