pola-rs/polars · error

read an Array from a non-Array data type

Error message

read an Array from a non-Array data type

What it means

The public json::deserialize(json, dtype, ...) requires that when the top-level JSON value is an Array, the target dtype is LargeList - it dispatches to _deserialize on the inner elements. Any other dtype with an array root hits todo!(). It is a caller-contract violation: array-shaped JSON must target a list type; scalar dtypes must be fed element-wise (which is what internal callers do).

Source

Thrown at crates/polars-json/src/json/deserialize.rs:551

            allow_extra_fields_in_struct,
        )?)),
        adt => polars_bail!(
            ComputeError: "deserialization from JSON is not implemented for `{adt:?}`"
        ),
    }
}

pub fn deserialize(
    json: &BorrowedValue,
    dtype: ArrowDataType,
    allow_extra_fields_in_struct: bool,
) -> PolarsResult<Box<dyn Array>> {
    match json {
        BorrowedValue::Array(rows) => match dtype {
            ArrowDataType::LargeList(inner) => {
                _deserialize(rows, inner.dtype, allow_extra_fields_in_struct)
            },
            _ => todo!("read an Array from a non-Array data type"),
        },
        _ => _deserialize(&[json], dtype, allow_extra_fields_in_struct),
    }
}

fn check_err_idx<'a>(
    rows: &[impl Borrow<BorrowedValue<'a>>],
    err_idx: usize,
    type_name: &'static str,
) -> PolarsResult<()> {
    if err_idx != rows.len() {
        polars_bail!(
            ComputeError:
            r#"error deserializing value "{:?}" as {}.

Try increasing `infer_schema_length` or specifying a schema."#,
            rows[err_idx].borrow(), type_name,
        )

View on GitHub (pinned to 68506541d2)

Solutions

  1. Wrap the target dtype: pass ArrowDataType::LargeList(inner) when the root is an array
  2. Or flatten first: iterate the array and call deserialize per element with the scalar dtype
  3. Check the root variant (BorrowedValue::Array vs other) before choosing the dtype

Example fix

// before
deserialize(&json_array, ArrowDataType::Int64, true)  // todo!()

// after
deserialize(&json_array, ArrowDataType::LargeList(Box::new(Field::new("item", ArrowDataType::Int64, true))), true)
// or: for v in array_elements { deserialize(&v, ArrowDataType::Int64, true)?; }
Defensive patterns

Strategy: type-guard

Validate before calling

use polars_json::json::BorrowedValue;
fn root_matches_dtype(v: &BorrowedValue, dtype: &ArrowDataType) -> bool {
    match (v, dtype) {
        (BorrowedValue::Array(_), ArrowDataType::LargeList(_)) => true,
        (BorrowedValue::Array(_), _) => false,
        (_, ArrowDataType::LargeList(_)) => false,
        _ => true,
    }
}

Type guard

fn target_dtype_for_root(v: &BorrowedValue, elem: ArrowDataType) -> ArrowDataType {
    match v {
        BorrowedValue::Array(_) => ArrowDataType::LargeList(Box::new(
            ArrowField::new("item", elem, true).into(),
        )),
        _ => elem,
    }
}

Prevention

When it happens

Trigger: Calling polars_json::json::deserialize(&borrowed_value, ArrowDataType::Int64, ...) where borrowed_value is a JSON array like [1,2,3]; custom integrations that pass serde/simd-json parsed bodies straight through without checking the root shape.

Common situations: Hand-rolled interop feeding arbitrary JSON bodies to deserialize; assuming lenient coercion (array -> first element, single-element array -> scalar).

Related errors


AI-assisted analysis of pola-rs/polars@68506541d2 (2026-08-19). Data as JSON: /api/errors/4f0fd4f446fe47b8. Report an issue: GitHub.