{"record":{"id":"dc8b2d901764fd83","repo":"astral-sh/ruff","slug":"invalid-collection-element-type-rule","errorCode":null,"errorMessage":"Invalid collection element type: {rule}","messagePattern":"Invalid collection element type: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"crates/ruff_python_ast/generate.py","lineNumber":284,"sourceCode":"    sequence_kind: SequenceKind | None = None\n    optional: bool = False\n\n    def __init__(self, rule: str) -> None:\n        self.rule = rule\n        self.optional = False\n        if \"?\" in rule:\n            if not rule.endswith(\"?\") or rule.count(\"?\") != 1:\n                raise ValueError(f\"`?` must be at the end: {rule}\")\n            self.optional = True\n            rule = rule[:-1]\n\n        self.sequence_kind, self.name = split_sequence_type(rule)\n        if self.optional and self.sequence_kind is not None:\n            raise ValueError(f\"optional field cannot be sequence or slice: {self.rule}\")\n        if self.sequence_kind is not None and (\n            not self.name or any(ch in self.name for ch in \"?*&[]<>\")\n        ):\n            raise ValueError(f\"Invalid collection element type: {rule}\")\n\n        self.inner = extract_type_argument(self.name)\n\n\n# ------------------------------------------------------------------------------\n# Preamble\n\n\ndef write_preamble(out: list[str]) -> None:\n    out.append(\"\"\"\n    // This is a generated file. Don't modify it by hand!\n    // Run `crates/ruff_python_ast/generate.py` to re-generate the file.\n\n    use crate::name::Name;\n    use crate::visitor::source_order::SourceOrderVisitor;\n    \"\"\")\n\n","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ruff_python_ast/generate.py#L266-L302","documentation":"For sequence fields the generator requires a bare element type name. FieldType.__init__ raises this ValueError when the extracted element is empty ('Vec<>') or contains any of the characters ? * & [ ] < > — which rules out nested generics like 'Vec<Box<Expr>>' or 'Box<[Vec<Stmt>]>', because the codegen cannot synthesize element accessors for such types.","triggerScenarios":"Writing a sequence rule whose element is empty or itself generic: 'Vec<>', 'Vec<Box<Expr>>', 'Box<[Vec<Stmt>]>', then running generate.py.","commonSituations":"Trying to double-box elements by hand; porting hand-written AST structs that used nested collections; assuming the generator needs explicit boxing inside sequences.","solutions":["Use a bare type name as the element ('Vec<Expr>'); the generator inserts boxing where the node definition requires it.","If elements must be shared or complex, introduce a distinct AST node type instead of nesting generics in the rule.","Re-run the generator and verify the produced Rust field type."],"exampleFix":"# before\nvalues: Vec<Box<Expr>>\n\n# after (element must be a bare type name)\nvalues: Vec<Expr>","handlingStrategy":"validation","validationCode":"BAD_CHARS = set('?*&[]<>')\n\n\ndef element_ok(rule: str) -> bool:\n    for prefix, suffix in (('Vec<', '>'), ('ThinVec<', '>'), ('Box<[', ']>')):\n        if rule.startswith(prefix) and rule.endswith(suffix):\n            element = rule[len(prefix):-len(suffix)]\n            return bool(element) and not BAD_CHARS & set(element)\n    return True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Sequence elements must be bare type names; the generator handles boxing.","Introduce a dedicated node type instead of nesting generics in a rule."],"tags":["codegen","rust-ast","nested-generics","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"}