fishaudio/fish-speech · error · UnbalancedBracesError

Unbalanced braces

Error message

Unbalanced braces

What it means

While splitting a brace expression on top-level commas, parse_sequence detects an unterminated bracket and raises UnbalancedBracesError (the bare constructor yields the default 'Unbalanced braces' message).

Source

Thrown at fish_speech/utils/braceexpand.py:178

    bracketdepth = 0
    items: list[Iterable[str]] = []

    # print 'sequence:', seq
    while pos < len(seq):
        if escape and seq[pos] == "\\":
            pos += 2
            continue
        elif seq[pos] == "{":
            bracketdepth += 1
        elif seq[pos] == "}":
            bracketdepth -= 1
        elif seq[pos] == "," and bracketdepth == 0:
            items.append(parse_pattern(seq[start:pos], escape))
            start = pos + 1  # skip the comma
        pos += 1

    if bracketdepth != 0:
        raise UnbalancedBracesError
    if not items:
        return None

    # part after the last comma (may be the empty string)
    items.append(parse_pattern(seq[start:], escape))
    return chain(*items)


def make_int_range(left: str, right: str, incr: Optional[str] = None) -> Iterator[str]:
    if any([s.startswith(("0", "-0")) for s in (left, right) if s not in ("0", "-0")]):
        padding = max(len(left), len(right))
    else:
        padding = 0
    step = (int(incr) or 1) if incr else 1
    start = int(left)
    end = int(right)
    r = range(start, end + 1, step) if start < end else range(start, end - 1, -step)
    fmt = "%0{}d".format(padding)

View on GitHub (pinned to befe400174)

Solutions

  1. Rewrite the pattern with matched braces at every nesting level
  2. Test nested patterns with small examples before production use
  3. Catch UnbalancedBracesError around user-facing pattern expansion
Defensive patterns

Strategy: try-catch

Validate before calling

def braces_balanced(s, i=0, depth=0):
    while i < len(s):
        if s[i] == "\\": i += 2; continue
        if s[i] == "{": depth += 1
        elif s[i] == "}": depth -= 1
        i += 1
    return depth == 0

Try / catch

from fish_speech.utils.braceexpand import UnbalancedBracesError
try:
    expanded = list(braceexpand(pattern))
except UnbalancedBracesError:
    expanded = [pattern]  # fall back to literal

Prevention

When it happens

Trigger: Expanding a nested/sequence pattern where a '{' inside the sequence is never closed, e.g. '{a{1,2,b}' or '{x,'.

Common situations: Nested brace patterns built programmatically; truncated user input; patterns passed through a layer that strips characters.

Related errors


AI-assisted analysis of fishaudio/fish-speech@befe400174 (2026-08-27). Data as JSON: /api/errors/91fe33caa33f5f6f. Report an issue: GitHub.