xai-org/x-algorithm · error · anyhow::Error

not StructArray

Error message

not StructArray

What it means

The elements of the user_actions list must be a StructArray (each action a struct with feature fields). After taking list.value(0), the code downcasts to StructArray; if the list's value type is not a struct (e.g. primitives or a nested list), this error is raised. It also guards against a 'zero actions' bail immediately after.

Source

Thrown at bdsm/rust/abuse-v3-features/src/lib.rs:273

        arrow::compute::concat_batches(&batches[0].schema(), &batches)?
    };

    let actions_col = batch
        .column_by_name("user_actions")
        .ok_or_else(|| anyhow::anyhow!("no user_actions"))?;
    let list = actions_col
        .as_any()
        .downcast_ref::<ListArray>()
        .ok_or_else(|| anyhow::anyhow!("not ListArray"))?;
    if list.is_empty() || list.is_null(0) {
        anyhow::bail!("empty list");
    }

    let vals = list.value(0);
    let sa = vals
        .as_any()
        .downcast_ref::<StructArray>()
        .ok_or_else(|| anyhow::anyhow!("not StructArray"))?;
    let total = sa.len();
    if total == 0 {
        anyhow::bail!("zero actions");
    }

    let start = if total > seq_len { total - seq_len } else { 0 };
    let take = total.min(seq_len);
    let sl = sa.slice(start, take);
    let sl = sl.as_any().downcast_ref::<StructArray>().unwrap();
    let n = take;

    Ok(UserArrowFeatures {
        n,
        action_name: get_i32(sl, "action_name"),
        tweet_id: get_i64(sl, "tweet_id"),
        author_id: get_i64(sl, "author_id"),
        engagement_time_ms: get_i64(sl, "engagement_time_ms"),
        dwell_time: get_i32(sl, "dwell_time"),

View on GitHub (pinned to 24c60942c5)

Solutions

  1. Inspect list.value_type() / the inner DataType and compare against the expected struct fields
  2. Fix the producer to emit list<struct<...>> with the agreed field set
  3. Update this consumer to handle the new inner type if the change is intentional
  4. Add a schema contract check (expected inner struct fields) before extraction runs

Example fix

// before
let sa = vals
    .as_any()
    .downcast_ref::<StructArray>()
    .ok_or_else(|| anyhow::anyhow!("not StructArray"))?;

// after
let sa = vals
    .as_any()
    .downcast_ref::<StructArray>()
    .ok_or_else(|| anyhow::anyhow!(
        "not StructArray: inner type is {:?}",
        vals.data_type()
    ))?;
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate inner element type before extraction
if let Some(col) = batch.column_by_name("user_actions") {
    if let DataType::List(f) = col.data_type() {
        anyhow::ensure!(matches!(f.data_type(), DataType::Struct(_)), "inner type must be struct");
    }
}

Type guard

fn actions_are_structs(list: &ListArray) -> bool {
    matches!(list.value_type(), DataType::Struct(_))
}

Try / catch

// verify inner type, then downcast safely
let vals = list.value(0);
let sa = vals.as_any().downcast_ref::<StructArray>()
    .ok_or_else(|| anyhow::anyhow!("expected struct inner type, got {:?}", vals.data_type()))?;

Prevention

When it happens

Trigger: Calling extract_batch where the list's inner type is not Struct — producer changed the element type, or the actions structs were flattened/unnested upstream.

Common situations: Schema evolution of the action struct (fields added/removed and re-encoded differently), producers writing list<list<...>> or list<string> variants, or mismatched versions between the feature-generation job and this library.

Related errors


AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28). Data as JSON: /api/errors/d8b3fde657159fe4. Report an issue: GitHub.