pola-rs/polars · error

StructArray must be initialized with DataType::Struct

Error message

StructArray must be initialized with DataType::Struct

What it means

StructArray::new_empty only accepts an ArrowDataType whose to_storage() is Struct(fields): it needs the field list to build one empty child array per field. Any other dtype panics because there is no field set to construct children from.

Source

Thrown at crates/polars-arrow/src/array/struct_/mod.rs:134

    pub fn new(
        dtype: ArrowDataType,
        length: usize,
        values: Vec<Box<dyn Array>>,
        validity: Option<Bitmap>,
    ) -> Self {
        Self::try_new(dtype, length, values, validity).unwrap()
    }

    /// Creates an empty [`StructArray`].
    pub fn new_empty(dtype: ArrowDataType) -> Self {
        if let ArrowDataType::Struct(fields) = &dtype.to_storage() {
            let values = fields
                .iter()
                .map(|field| new_empty_array(field.dtype().clone()))
                .collect();
            Self::new(dtype, 0, values, None)
        } else {
            panic!("StructArray must be initialized with DataType::Struct");
        }
    }

    /// Creates a null [`StructArray`] of length `length`.
    pub fn new_null(dtype: ArrowDataType, length: usize) -> Self {
        if let ArrowDataType::Struct(fields) = &dtype {
            let values = fields
                .iter()
                .map(|field| new_null_array(field.dtype().clone(), length))
                .collect();
            Self::new(dtype, length, values, Some(Bitmap::new_zeroed(length)))
        } else {
            panic!("StructArray must be initialized with DataType::Struct");
        }
    }
}

// must use

View on GitHub (pinned to 9b5d73fd00)

Solutions

  1. Use the generic dispatcher polars_arrow::array::new_empty_array(dtype) instead of calling StructArray::new_empty directly
  2. Match on matches!(dtype.to_storage(), ArrowDataType::Struct(_)) before calling and handle other variants explicitly
  3. Return a proper unsupported-dtype error for unexpected variants instead of reaching the panic

Example fix

// before
let empty = StructArray::new_empty(dtype);

// after
let empty = polars_arrow::array::new_empty_array(dtype);
Defensive patterns

Strategy: type-guard

Validate before calling

fn struct_only(dtype: &ArrowDataType) -> Result<&ArrowDataType, String> {
    match dtype.to_storage() {
        ArrowDataType::Struct(_) => Ok(dtype),
        other => Err(format!("expected Struct dtype, got {other:?}")),
    }
}

Type guard

fn is_struct_dtype(dtype: &ArrowDataType) -> bool {
    matches!(dtype.to_storage(), ArrowDataType::Struct(_))
}

Prevention

When it happens

Trigger: StructArray::new_empty(ArrowDataType::Null) or new_empty(List(..)) — usually reached from generic code that special-cases struct handling but falls through to the concrete constructor for non-struct dtypes.

Common situations: Schema evolution delivering a non-struct dtype where code assumed structs; matching on a logical/extension type whose storage is not Struct; copy-pasted empty-batch construction for heterogeneous schemas.

Related errors


AI-assisted analysis of pola-rs/polars@9b5d73fd00 (2026-08-19). Data as JSON: /api/errors/33810420fc4647c6. Report an issue: GitHub.