{"record":{"id":"80cf0bfa70f3bbbe","repo":"astral-sh/ruff","slug":"brackets-are-not-balanced-for-type-rust-type-str","errorCode":null,"errorMessage":"Brackets are not balanced for type {rust_type_str}","messagePattern":"Brackets are not balanced for type (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"crates/ruff_python_ast/generate.py","lineNumber":227,"sourceCode":"            \"u32\",\n            \"bool\",\n            \"Number\",\n            \"IpyEscapeKind\",\n        ]\n\n\n# Extracts the type argument from a Rust type used in AST field syntax.\n# Box<str> -> str\n# Box<Expr> -> Expr\n# If the type does not have a type argument, it will return the string.\n# Does not support nested types\ndef extract_type_argument(rust_type_str: str) -> str:\n    open_bracket_index = rust_type_str.find(\"<\")\n    if open_bracket_index == -1:\n        return rust_type_str\n    close_bracket_index = rust_type_str.rfind(\">\")\n    if close_bracket_index == -1 or close_bracket_index <= open_bracket_index:\n        raise ValueError(f\"Brackets are not balanced for type {rust_type_str}\")\n    inner_type = rust_type_str[open_bracket_index + 1 : close_bracket_index].strip()\n    inner_type = inner_type.replace(\"crate::\", \"\")\n    return inner_type\n\n\nclass SequenceKind(Enum):\n    VEC = \"vec\"\n    BOXED_SLICE = \"boxed_slice\"\n    THIN_VEC = \"thin_vec\"\n\n\ndef split_sequence_type(rule: str) -> tuple[SequenceKind | None, str]:\n    if \"&\" in rule:\n        raise ValueError(f\"`&T*` is unsupported; use `Box<[T]>`: {rule}\")\n\n    if \"*\" in rule:\n        if rule.endswith(\"*\") and rule.count(\"*\") == 1:\n            return SequenceKind.VEC, rule[:-1]","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ruff_python_ast/generate.py#L209-L245","documentation":"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.","triggerScenarios":"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 '<'.","commonSituations":"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.","solutions":["Open the AST definition the generator was consuming and balance the generic brackets (find the '<' that has no matching '>').","Re-run python crates/ruff_python_ast/generate.py and review the regenerated diff.","Run cargo check -p ruff_python_ast to confirm the regenerated code compiles."],"exampleFix":"# before (AST field rule)\ndecorator_list: Box<Expr\n\n# after\ndecorator_list: Box<Expr>","handlingStrategy":"validation","validationCode":"def generics_balanced(t: str) -> bool:\n    i, j = t.find('<'), t.rfind('>')\n    return i == -1 or (j != -1 and j > i)\n\n\n# run over every field rule before invoking generate.py\nassert all(generics_balanced(rule) for rule in field_rules)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run cargo dev generate-all locally before committing AST changes; it fails fast on malformed rules.","Keep field types in the documented shapes: T, T?, T*, Vec<T>, ThinVec<T>, Box<[T]>, Box<T>.","Review the generated diff in the PR so DSL typos surface immediately."],"tags":["codegen","python","rust-ast","developer-tooling"],"backgroundTag":"codegen-dsl-parse-error","analyzedSha":"d1087a4b9e03d253a88703f34e0869ee4b805456","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}