astral-sh/ruff · error · ValueError

Invalid collection element type: {rule}

Error message

Invalid collection element type: {rule}

What it means

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.

Source

Thrown at crates/ruff_python_ast/generate.py:284

    sequence_kind: SequenceKind | None = None
    optional: bool = False

    def __init__(self, rule: str) -> None:
        self.rule = rule
        self.optional = False
        if "?" in rule:
            if not rule.endswith("?") or rule.count("?") != 1:
                raise ValueError(f"`?` must be at the end: {rule}")
            self.optional = True
            rule = rule[:-1]

        self.sequence_kind, self.name = split_sequence_type(rule)
        if self.optional and self.sequence_kind is not None:
            raise ValueError(f"optional field cannot be sequence or slice: {self.rule}")
        if self.sequence_kind is not None and (
            not self.name or any(ch in self.name for ch in "?*&[]<>")
        ):
            raise ValueError(f"Invalid collection element type: {rule}")

        self.inner = extract_type_argument(self.name)


# ------------------------------------------------------------------------------
# Preamble


def write_preamble(out: list[str]) -> None:
    out.append("""
    // This is a generated file. Don't modify it by hand!
    // Run `crates/ruff_python_ast/generate.py` to re-generate the file.

    use crate::name::Name;
    use crate::visitor::source_order::SourceOrderVisitor;
    """)

View on GitHub (pinned to d1087a4b9e)

Solutions

  1. Use a bare type name as the element ('Vec<Expr>'); the generator inserts boxing where the node definition requires it.
  2. If elements must be shared or complex, introduce a distinct AST node type instead of nesting generics in the rule.
  3. Re-run the generator and verify the produced Rust field type.

Example fix

# before
values: Vec<Box<Expr>>

# after (element must be a bare type name)
values: Vec<Expr>
Defensive patterns

Strategy: validation

Validate before calling

BAD_CHARS = set('?*&[]<>')


def element_ok(rule: str) -> bool:
    for prefix, suffix in (('Vec<', '>'), ('ThinVec<', '>'), ('Box<[', ']>')):
        if rule.startswith(prefix) and rule.endswith(suffix):
            element = rule[len(prefix):-len(suffix)]
            return bool(element) and not BAD_CHARS & set(element)
    return True

Prevention

When it happens

Trigger: Writing a sequence rule whose element is empty or itself generic: 'Vec<>', 'Vec<Box<Expr>>', 'Box<[Vec<Stmt>]>', then running generate.py.

Common situations: Trying to double-box elements by hand; porting hand-written AST structs that used nested collections; assuming the generator needs explicit boxing inside sequences.

Related errors


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