{"record":{"id":"04a5deef4c061f3d","repo":"microsoft/playwright","slug":"invalid-glob-pattern-json-stringify-glob-unma","errorCode":null,"errorMessage":"Invalid glob pattern ${JSON.stringify(glob)}: unmatched '}'","messagePattern":"Invalid glob pattern (.+?): unmatched '\\}'","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/isomorphic/urlMatch.ts","lineNumber":74,"sourceCode":"        } else {\n          tokens.push('(.*)');\n        }\n      } else {\n        tokens.push('([^/]*)');\n      }\n      continue;\n    }\n\n    switch (c) {\n      case '{':\n        if (inGroup)\n          throw new Error(`Invalid glob pattern ${JSON.stringify(glob)}: nested '{' is not supported`);\n        inGroup = true;\n        tokens.push('(');\n        break;\n      case '}':\n        if (!inGroup)\n          throw new Error(`Invalid glob pattern ${JSON.stringify(glob)}: unmatched '}'`);\n        inGroup = false;\n        tokens.push(')');\n        break;\n      case ',':\n        if (inGroup) {\n          tokens.push('|');\n          break;\n        }\n        tokens.push('\\\\' + c);\n        break;\n      default:\n        tokens.push(escapedChars.has(c) ? '\\\\' + c : c);\n    }\n  }\n  if (inGroup)\n    throw new Error(`Invalid glob pattern ${JSON.stringify(glob)}: unmatched '{'`);\n  tokens.push('$');\n  return tokens.join('');","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/isomorphic/urlMatch.ts#L56-L92","documentation":"Thrown by globToRegexPattern when a `}` is encountered while not inside a brace group (inGroup is false). It indicates an unbalanced closing brace with no matching opening `{`, which the converter cannot turn into a valid regex.","triggerScenarios":"Passing a glob with a stray `}`, e.g. `'**/api}'`, `page.route('**/foo,bar}', ...)`, or any glob where `}` appears without a preceding `{`. Triggered in the `case '}'` branch when inGroup is false.","commonSituations":"Typo in a URL glob; truncation that drops the opening brace; JSON/templating that injects a stray closing brace; mis-pasting a pattern fragment.","solutions":["Add the matching opening `{` or remove the stray `}`.","Escape the brace if it is literal: `\\}`.","Reconstruct the glob from known-good parts and log it before registering the route."],"exampleFix":"// before\npage.route('**/api}', handler);  // unmatched }\n\n// after\npage.route('**/api', handler);  // or '**/\\}' for literal brace","handlingStrategy":"validation","validationCode":"function assertBracesBalanced(glob: string) {\n  let depth = 0;\n  for (const c of glob) {\n    if (c === '{') depth++;\n    else if (c === '}') depth--;\n    if (depth < 0) throw new Error(`Glob has unmatched }: ${glob}`);\n  }\n  if (depth !== 0) throw new Error(`Glob has unmatched {: ${glob}`);\n}","typeGuard":"function hasBalancedBraces(glob: string): boolean {\n  let depth = 0;\n  for (const c of glob) {\n    if (c === '{') depth++;\n    else if (c === '}') depth--;\n    if (depth < 0) return false;\n  }\n  return depth === 0;\n}","tryCatchPattern":"try {\n  page.route(glob, handler);\n} catch (e) {\n  if (/unmatched '\\}'/.test(e.message)) {\n    glob = glob.replace(/(^|[^{])}/g, '$1\\\\}'); // escape stray brace\n    page.route(glob, handler);\n  } else throw e;\n}","preventionTips":["Escape literal braces with `\\{`/`\\}`.","Log dynamically built globs before registration.","Reject brace imbalance at config-load time."],"tags":["glob","url-matching","parsing","validation"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}