astral-sh/ruff · error · ValueError

Brackets are not balanced for type {rust_type_str}

Error message

Brackets are not balanced for type {rust_type_str}

What it means

generate.py is the maintainer code-generation script that regenerates the ruff_python_ast sources. extract_type_argument() takes a Rust field type such as Box<Expr> or Vec<Stmt> and returns the generic argument (stripping a crate:: prefix). It raises ValueError when a rule string contains '<' but the last '>' is missing or occurs at or before the '<' — i.e. the generic brackets of an AST field rule are unbalanced.

Source

Thrown at crates/ruff_python_ast/generate.py:227

            "u32",
            "bool",
            "Number",
            "IpyEscapeKind",
        ]


# Extracts the type argument from a Rust type used in AST field syntax.
# Box<str> -> str
# Box<Expr> -> Expr
# If the type does not have a type argument, it will return the string.
# Does not support nested types
def extract_type_argument(rust_type_str: str) -> str:
    open_bracket_index = rust_type_str.find("<")
    if open_bracket_index == -1:
        return rust_type_str
    close_bracket_index = rust_type_str.rfind(">")
    if close_bracket_index == -1 or close_bracket_index <= open_bracket_index:
        raise ValueError(f"Brackets are not balanced for type {rust_type_str}")
    inner_type = rust_type_str[open_bracket_index + 1 : close_bracket_index].strip()
    inner_type = inner_type.replace("crate::", "")
    return inner_type


class SequenceKind(Enum):
    VEC = "vec"
    BOXED_SLICE = "boxed_slice"
    THIN_VEC = "thin_vec"


def split_sequence_type(rule: str) -> tuple[SequenceKind | None, str]:
    if "&" in rule:
        raise ValueError(f"`&T*` is unsupported; use `Box<[T]>`: {rule}")

    if "*" in rule:
        if rule.endswith("*") and rule.count("*") == 1:
            return SequenceKind.VEC, rule[:-1]

View on GitHub (pinned to d1087a4b9e)

Solutions

  1. Open the AST definition the generator was consuming and balance the generic brackets (find the '<' that has no matching '>').
  2. Re-run python crates/ruff_python_ast/generate.py and review the regenerated diff.
  3. Run cargo check -p ruff_python_ast to confirm the regenerated code compiles.

Example fix

# before (AST field rule)
decorator_list: Box<Expr

# after
decorator_list: Box<Expr>
Defensive patterns

Strategy: validation

Validate before calling

def generics_balanced(t: str) -> bool:
    i, j = t.find('<'), t.rfind('>')
    return i == -1 or (j != -1 and j > i)


# run over every field rule before invoking generate.py
assert all(generics_balanced(rule) for rule in field_rules)

Prevention

When it happens

Trigger: Running python crates/ruff_python_ast/generate.py (or cargo dev generate-all) after editing the AST definitions so a field type reads like 'Box<Expr', 'Vec<Stmt', or has the closing '>' before the opening '<'.

Common situations: Hand-editing AST node definitions and dropping a closing bracket; truncating a type during copy-paste from Rust source; renaming a type mid-refactor and losing a bracket.

Related errors


AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20). Data as JSON: /api/errors/80cf0bfa70f3bbbe. Report an issue: GitHub.