oraios/serena · error
Invalid glob brace expression in
Error message
Invalid glob brace expression in {pattern!r}: unmatched brace What it means
_expand_braces loops expanding innermost brace groups while a {...} matches; if braces remain unbalanced (an opening brace with no matching close), the regex finds nothing and it raises ValueError 'unmatched brace'. This prevents silently treating malformed globs as literal patterns.
Solutions
- Balance the braces in the pattern, e.g. 'src/*.{py,pyi}'
- Remove braces if no alternation is intended
- Pre-validate the pattern with a quick brace-balance check before calling
- Catch ValueError and surface a pattern-syntax error to the user
Example fix
// before
pattern = 'src/*{.py'
// after
pattern = 'src/*.{py}' # or simply 'src/*.py' Defensive patterns
Strategy: validation
Validate before calling
def braces_balanced(pattern: str) -> bool:
return pattern.count("{") == pattern.count("}")
if not braces_balanced(glob):
raise ValueError(f"unbalanced braces in {glob!r}") Try / catch
try:
expanded = GlobPattern(pat)
except ValueError as e:
if "unmatched brace" in str(e):
log.error("Fix pattern syntax: %s", pat)
raise Prevention
- Balance-check braces before using brace-expansion globs
- Avoid building patterns via string concatenation that may truncate mid-brace
- Test glob expansion on representative inputs in unit tests
When it happens
Trigger: Passing patterns like 'src/*{.py' or 'a{b,c' where brace counts don't balance — the expansion loop terminates without consuming all braces and raises.
Common situations: Hand-written glob patterns with typos; string concatenation building patterns that cut off mid-brace; partially substituted templates.
Related errors
- Invalid glob brace expression in
- Invalid tool name
- Invalid topic
- Pass either content or source_file_path
- Tool named ' ' not found.
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/be6c1133a2cefc67.
Report an issue: GitHub.
Appendix: source
Thrown at src/serena/util/text_utils.py:237
Handles multiple brace sets as well.
"""
patterns = [pattern]
while any("{" in p or "}" in p for p in patterns):
new_patterns = []
for p in patterns:
match = re.search(r"\{([^{}]*)\}", p)
if match:
options_expr = match.group(1)
if not options_expr:
raise ValueError(f"Invalid glob brace expression in {pattern!r}: empty braces are not allowed")
prefix = p[: match.start()]
suffix = p[match.end() :]
options = options_expr.split(",")
for option in options:
new_patterns.append(f"{prefix}{option}{suffix}")
else:
raise ValueError(f"Invalid glob brace expression in {pattern!r}: unmatched brace")
patterns = new_patterns
return patterns
@staticmethod
def _translate_glob_to_regex(pattern: str) -> str:
res = []
i = 0
n = len(pattern)
while i < n:
c = pattern[i]
i += 1
if c == "*":
if i < n and pattern[i] == "*": # **
i += 1
if i < n and pattern[i] == "/": # **/
i += 1
if res and res[-1] == "/": # /**/
res = res[:-1]View on GitHub (pinned to 7fcbca7e62)